services added
This commit is contained in:
parent
d214bcae3c
commit
aabc1e9af8
|
|
@ -0,0 +1,28 @@
|
||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Use Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '22'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: 'npm ci'
|
||||||
|
|
||||||
|
- name: Run lint
|
||||||
|
run: 'npm run lint'
|
||||||
|
|
||||||
|
- name: Run build
|
||||||
|
run: 'npm run build'
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
module.exports = {
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#semicolons
|
||||||
|
*/
|
||||||
|
semi: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#trailing-commas
|
||||||
|
*/
|
||||||
|
trailingComma: 'all',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#bracket-spacing
|
||||||
|
*/
|
||||||
|
bracketSpacing: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#tabs
|
||||||
|
*/
|
||||||
|
useTabs: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#tab-width
|
||||||
|
*/
|
||||||
|
tabWidth: 2,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#arrow-function-parentheses
|
||||||
|
*/
|
||||||
|
arrowParens: 'always',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#quotes
|
||||||
|
*/
|
||||||
|
singleQuote: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#quote-props
|
||||||
|
*/
|
||||||
|
quoteProps: 'as-needed',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#end-of-line
|
||||||
|
*/
|
||||||
|
endOfLine: 'lf',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://prettier.io/docs/en/options.html#print-width
|
||||||
|
*/
|
||||||
|
printWidth: 100,
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"EditorConfig.EditorConfig",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Attach to running n8n",
|
||||||
|
"processId": "${command:PickProcess}",
|
||||||
|
"request": "attach",
|
||||||
|
"skipFiles": ["<node_internals>/**"],
|
||||||
|
"type": "node"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||||
|
level of experience, education, socio-economic status, nationality, personal
|
||||||
|
appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at jan@n8n.io. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see
|
||||||
|
https://www.contributor-covenant.org/faq
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
Copyright 2022 n8n
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
# n8n-nodes-_node-name_
|
||||||
|
|
||||||
|
This is an n8n community node. It lets you use _app/service name_ in your n8n workflows.
|
||||||
|
|
||||||
|
_App/service name_ is _one or two sentences describing the service this node integrates with_.
|
||||||
|
|
||||||
|
[n8n](https://n8n.io/) is a [fair-code licensed](https://docs.n8n.io/reference/license/) workflow automation platform.
|
||||||
|
|
||||||
|
[Installation](#installation)
|
||||||
|
[Operations](#operations)
|
||||||
|
[Credentials](#credentials) <!-- delete if no auth needed -->
|
||||||
|
[Compatibility](#compatibility)
|
||||||
|
[Usage](#usage) <!-- delete if not using this section -->
|
||||||
|
[Resources](#resources)
|
||||||
|
[Version history](#version-history) <!-- delete if not using this section -->
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Follow the [installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n community nodes documentation.
|
||||||
|
|
||||||
|
## Operations
|
||||||
|
|
||||||
|
_List the operations supported by your node._
|
||||||
|
|
||||||
|
## Credentials
|
||||||
|
|
||||||
|
_If users need to authenticate with the app/service, provide details here. You should include prerequisites (such as signing up with the service), available authentication methods, and how to set them up._
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
_State the minimum n8n version, as well as which versions you test against. You can also include any known version incompatibility issues._
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
_This is an optional section. Use it to help users with any difficult or confusing aspects of the node._
|
||||||
|
|
||||||
|
_By the time users are looking for community nodes, they probably already know n8n basics. But if you expect new users, you can link to the [Try it out](https://docs.n8n.io/try-it-out/) documentation to help them get started._
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
* [n8n community nodes documentation](https://docs.n8n.io/integrations/#community-nodes)
|
||||||
|
* _Link to app/service documentation._
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
_This is another optional section. If your node has multiple versions, include a short description of available versions and what changed, as well as any compatibility impact._
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { config } from '@n8n/node-cli/eslint';
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.0165 0C8.94791 0 0 9.01388 0 20.1653C0 29.0792 5.73324 36.6246 13.6868 39.2952C14.6812 39.496 15.0454 38.8613 15.0454 38.3274C15.0454 37.8599 15.0126 36.2575 15.0126 34.5879C9.4445 35.79 8.28498 32.1841 8.28498 32.1841C7.39015 29.847 6.06429 29.2463 6.06429 29.2463C4.24185 28.011 6.19704 28.011 6.19704 28.011C8.21861 28.1446 9.27938 30.081 9.27938 30.081C11.0686 33.1522 13.9518 32.2844 15.1118 31.7502C15.2773 30.4481 15.8079 29.5467 16.3713 29.046C11.9303 28.5785 7.25781 26.8425 7.25781 19.0967C7.25781 16.8932 8.05267 15.0905 9.31216 13.6884C9.11344 13.1877 8.41732 11.1174 9.51128 8.34644C9.51128 8.34644 11.2014 7.81217 15.0122 10.4164C16.6438 9.97495 18.3263 9.7504 20.0165 9.74851C21.7067 9.74851 23.4295 9.98246 25.0205 10.4164C28.8317 7.81217 30.5218 8.34644 30.5218 8.34644C31.6158 11.1174 30.9192 13.1877 30.7205 13.6884C32.0132 15.0905 32.7753 16.8932 32.7753 19.0967C32.7753 26.8425 28.1028 28.5449 23.6287 29.046C24.358 29.6802 24.9873 30.882 24.9873 32.7851C24.9873 35.4893 24.9545 37.6596 24.9545 38.327C24.9545 38.8613 25.3192 39.496 26.3132 39.2956C34.2667 36.6242 39.9999 29.0792 39.9999 20.1653C40.0327 9.01388 31.052 0 20.0165 0Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.0165 0C8.94791 0 0 9.01388 0 20.1653C0 29.0792 5.73324 36.6246 13.6868 39.2952C14.6812 39.496 15.0454 38.8613 15.0454 38.3274C15.0454 37.8599 15.0126 36.2575 15.0126 34.5879C9.4445 35.79 8.28498 32.1841 8.28498 32.1841C7.39015 29.847 6.06429 29.2463 6.06429 29.2463C4.24185 28.011 6.19704 28.011 6.19704 28.011C8.21861 28.1446 9.27938 30.081 9.27938 30.081C11.0686 33.1522 13.9518 32.2844 15.1118 31.7502C15.2773 30.4481 15.8079 29.5467 16.3713 29.046C11.9303 28.5785 7.25781 26.8425 7.25781 19.0967C7.25781 16.8932 8.05267 15.0905 9.31216 13.6884C9.11344 13.1877 8.41732 11.1174 9.51128 8.34644C9.51128 8.34644 11.2014 7.81217 15.0122 10.4164C16.6438 9.97495 18.3263 9.7504 20.0165 9.74851C21.7067 9.74851 23.4295 9.98246 25.0205 10.4164C28.8317 7.81217 30.5218 8.34644 30.5218 8.34644C31.6158 11.1174 30.9192 13.1877 30.7205 13.6884C32.0132 15.0905 32.7753 16.8932 32.7753 19.0967C32.7753 26.8425 28.1028 28.5449 23.6287 29.046C24.358 29.6802 24.9873 30.882 24.9873 32.7851C24.9873 35.4893 24.9545 37.6596 24.9545 38.327C24.9545 38.8613 25.3192 39.496 26.3132 39.2956C34.2667 36.6242 39.9999 29.0792 39.9999 20.1653C40.0327 9.01388 31.052 0 20.0165 0Z" fill="#24292F"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1 @@
|
||||||
|
import { IDataObject, INodeExecutionData, IExecuteFunctions } from 'n8n-workflow';
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: #e6244e;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path class="cls-1" d="M1410.69,1080H336.23v-225.18h983.63v-196.85H538.82c-135.08-7.21-202.59-53.13-202.59-137.81V128.33C336.23,49.07,403.68,6.3,538.62,0H1583.77V230.56H596.13v199.54h813.03c108.4,0,166.61,37.75,174.6,113.27v404.49c-8,88.11-65.68,132.14-173.08,132.14Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 506 B |
|
|
@ -0,0 +1,4 @@
|
||||||
|
export interface IErrorResponse {
|
||||||
|
errorCode: string;
|
||||||
|
errorMessage: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
export interface IFileUploadResponse {
|
||||||
|
fileStorageId: string;
|
||||||
|
fileName: string;
|
||||||
|
downloadUrl: string;
|
||||||
|
fileType: string;
|
||||||
|
fileSize: number;
|
||||||
|
secloreFileId: string;
|
||||||
|
protected: boolean;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
export interface ILoginRequest {
|
||||||
|
tenantId: string;
|
||||||
|
tenantSecret: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILoginResponse {
|
||||||
|
accessToken: string;
|
||||||
|
refreshToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRefreshTokenRequest {
|
||||||
|
refreshToken: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
export interface IExtRefProtectionDetail {
|
||||||
|
externalReferenceId: string;
|
||||||
|
externalReferenceName?: string;
|
||||||
|
externalReferenceData?: string;
|
||||||
|
externalAppId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProtectWithExternalRefIdRequest {
|
||||||
|
hotfolderExternalReference: IExtRefProtectionDetail;
|
||||||
|
fileExternalReference?: IExtRefProtectionDetail;
|
||||||
|
fileStorageId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProtectWithExternalRefIdResponse {
|
||||||
|
fileStorageId: string;
|
||||||
|
secloreFileId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProtectWithFileIdRequest {
|
||||||
|
existingProtectedFileId: string;
|
||||||
|
fileStorageId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProtectWithFileIdResponse {
|
||||||
|
fileStorageId: string;
|
||||||
|
secloreFileId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProtectWithHotFolderRequest {
|
||||||
|
hotfolderId: string;
|
||||||
|
fileStorageId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProtectWithHotFolderResponse {
|
||||||
|
fileStorageId: string;
|
||||||
|
secloreFileId: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
export interface IUnprotectRequest {
|
||||||
|
fileStorageId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IUnprotectResponse {
|
||||||
|
fileStorageId: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,384 @@
|
||||||
|
import { IExecuteFunctions, IHttpRequestOptions } from 'n8n-workflow';
|
||||||
|
import { ILoginRequest, ILoginResponse, IRefreshTokenRequest } from './Interfaces/LoginInterfaces';
|
||||||
|
import { IErrorResponse } from './Interfaces/ErrorInterfaces';
|
||||||
|
import { IProtectWithExternalRefIdRequest, IProtectWithExternalRefIdResponse, IProtectWithFileIdRequest, IProtectWithFileIdResponse, IProtectWithHotFolderRequest, IProtectWithHotFolderResponse } from './Interfaces/ProtectInterfaces';
|
||||||
|
import FormData from 'form-data';
|
||||||
|
import { IUnprotectRequest, IUnprotectResponse } from './Interfaces/UnprotectInterfaces';
|
||||||
|
import { IFileUploadResponse } from './Interfaces/FileStorageInterfaces';
|
||||||
|
|
||||||
|
export class SecloreDRMApiService {
|
||||||
|
private baseUrl: string;
|
||||||
|
|
||||||
|
constructor(private context: IExecuteFunctions, baseUrl: string) {
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login Endpoint to generate Access Token and Refresh Token for JWT Authorization.
|
||||||
|
* Upon successful login, all the existing previous tokens for that tenant will be invalidated.
|
||||||
|
*
|
||||||
|
* @param tenantId - The tenant ID
|
||||||
|
* @param tenantSecret - The tenant secret
|
||||||
|
* @param correlationId - Optional request ID for logging purpose
|
||||||
|
* @returns Promise<ILoginResponse> - Access token and refresh token
|
||||||
|
* @throws Error on authentication failure or server error
|
||||||
|
*/
|
||||||
|
async login(tenantId: string, tenantSecret: string, correlationId?: string): Promise<ILoginResponse> {
|
||||||
|
const requestBody: ILoginRequest = {
|
||||||
|
tenantId,
|
||||||
|
tenantSecret,
|
||||||
|
};
|
||||||
|
|
||||||
|
const headers: { [key: string]: string } = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add correlation ID if provided
|
||||||
|
if (correlationId) {
|
||||||
|
headers['X-SECLORE-CORRELATION-ID'] = correlationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.baseUrl}/seclore/drm/1.0/auth/login`,
|
||||||
|
headers,
|
||||||
|
body: requestBody,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.context.helpers.httpRequest(options);
|
||||||
|
return response as ILoginResponse;
|
||||||
|
} catch (error: any) {
|
||||||
|
// Handle specific HTTP error responses
|
||||||
|
if (error.statusCode === 401) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Unauthorized: ${errorResponse?.errorMessage || 'Invalid credentials'}`);
|
||||||
|
} else if (error.statusCode === 500) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Server Error: ${errorResponse?.errorMessage || 'Internal server error'}`);
|
||||||
|
}
|
||||||
|
// Re-throw other errors
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Endpoint for generating new Access Token and Refresh Token using an existing valid Refresh Token.
|
||||||
|
* Upon successful response, all the previous existing Access Tokens and Refresh Tokens of that tenant will be invalidated.
|
||||||
|
*
|
||||||
|
* @param refreshToken - The existing valid refresh token
|
||||||
|
* @param correlationId - Optional request ID for logging purpose
|
||||||
|
* @returns Promise<ILoginResponse> - New access token and refresh token
|
||||||
|
* @throws Error on authentication failure or server error
|
||||||
|
*/
|
||||||
|
async refreshToken(refreshToken: string, correlationId?: string): Promise<ILoginResponse> {
|
||||||
|
const requestBody: IRefreshTokenRequest = {
|
||||||
|
refreshToken,
|
||||||
|
};
|
||||||
|
|
||||||
|
const headers: { [key: string]: string } = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add correlation ID if provided
|
||||||
|
if (correlationId) {
|
||||||
|
headers['X-SECLORE-CORRELATION-ID'] = correlationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.baseUrl}/seclore/drm/1.0/auth/refresh`,
|
||||||
|
headers,
|
||||||
|
body: requestBody,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.context.helpers.httpRequest(options);
|
||||||
|
return response as ILoginResponse;
|
||||||
|
} catch (error: any) {
|
||||||
|
// Handle specific HTTP error responses
|
||||||
|
if (error.statusCode === 401) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Unauthorized: ${errorResponse?.errorMessage || 'Invalid refresh token'}`);
|
||||||
|
} else if (error.statusCode === 500) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Server Error: ${errorResponse?.errorMessage || 'Internal server error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-throw other errors
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protect file using external identifier of protected File and HotFolder with PS configured against the logged in Tenant in application.
|
||||||
|
*
|
||||||
|
* @param protectRequest - The protection request details
|
||||||
|
* @param accessToken - JWT access token for authorization
|
||||||
|
* @param correlationId - Optional request ID for logging purpose
|
||||||
|
* @returns Promise<IProtectWithExternalRefIdResponse> - File storage ID and Seclore file ID
|
||||||
|
* @throws Error on bad request, authentication failure or server error
|
||||||
|
*/
|
||||||
|
async protectWithExternalRefId(
|
||||||
|
protectRequest: IProtectWithExternalRefIdRequest,
|
||||||
|
accessToken: string,
|
||||||
|
correlationId?: string
|
||||||
|
): Promise<IProtectWithExternalRefIdResponse> {
|
||||||
|
const headers: { [key: string]: string } = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add correlation ID if provided
|
||||||
|
if (correlationId) {
|
||||||
|
headers['X-SECLORE-CORRELATION-ID'] = correlationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.baseUrl}/seclore/drm/1.0/protect/externalref`,
|
||||||
|
headers,
|
||||||
|
body: protectRequest,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.context.helpers.httpRequest(options);
|
||||||
|
return response as IProtectWithExternalRefIdResponse;
|
||||||
|
} catch (error: any) {
|
||||||
|
// Handle specific HTTP error responses
|
||||||
|
if (error.statusCode === 400) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Bad Request: ${errorResponse?.errorMessage || 'Invalid request data'}`);
|
||||||
|
} else if (error.statusCode === 401) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Unauthorized: ${errorResponse?.errorMessage || 'Invalid access token'}`);
|
||||||
|
} else if (error.statusCode === 500) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Server Error: ${errorResponse?.errorMessage || 'Internal server error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-throw other errors
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protects file using File ID of already protected file with PS configured against the logged in Tenant in application.
|
||||||
|
*
|
||||||
|
* @param protectRequest - The protection request details with existing protected file ID
|
||||||
|
* @param accessToken - JWT access token for authorization
|
||||||
|
* @param correlationId - Optional request ID for logging purpose
|
||||||
|
* @returns Promise<IProtectWithFileIdResponse> - File storage ID and Seclore file ID
|
||||||
|
* @throws Error on bad request, authentication failure or server error
|
||||||
|
*/
|
||||||
|
async protectWithFileId(
|
||||||
|
protectRequest: IProtectWithFileIdRequest,
|
||||||
|
accessToken: string,
|
||||||
|
correlationId?: string
|
||||||
|
): Promise<IProtectWithFileIdResponse> {
|
||||||
|
const headers: { [key: string]: string } = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add correlation ID if provided
|
||||||
|
if (correlationId) {
|
||||||
|
headers['X-SECLORE-CORRELATION-ID'] = correlationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.baseUrl}/seclore/drm/1.0/protect/fileid`,
|
||||||
|
headers,
|
||||||
|
body: protectRequest,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.context.helpers.httpRequest(options);
|
||||||
|
return response as IProtectWithFileIdResponse;
|
||||||
|
} catch (error: any) {
|
||||||
|
// Handle specific HTTP error responses
|
||||||
|
if (error.statusCode === 400) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Bad Request: ${errorResponse?.errorMessage || 'Invalid request data'}`);
|
||||||
|
} else if (error.statusCode === 401) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Unauthorized: ${errorResponse?.errorMessage || 'Invalid access token'}`);
|
||||||
|
} else if (error.statusCode === 500) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Server Error: ${errorResponse?.errorMessage || 'Internal server error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-throw other errors
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protects file using HotFolder ID with PS configured against the logged in Tenant in application.
|
||||||
|
*
|
||||||
|
* @param protectRequest - The protection request details with hotfolder ID
|
||||||
|
* @param accessToken - JWT access token for authorization
|
||||||
|
* @param correlationId - Optional request ID for logging purpose
|
||||||
|
* @returns Promise<IProtectWithHotFolderResponse> - File storage ID and Seclore file ID
|
||||||
|
* @throws Error on bad request, authentication failure or server error
|
||||||
|
*/
|
||||||
|
async protectWithHotFolder(
|
||||||
|
protectRequest: IProtectWithHotFolderRequest,
|
||||||
|
accessToken: string,
|
||||||
|
correlationId?: string
|
||||||
|
): Promise<IProtectWithHotFolderResponse> {
|
||||||
|
const headers: { [key: string]: string } = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add correlation ID if provided
|
||||||
|
if (correlationId) {
|
||||||
|
headers['X-SECLORE-CORRELATION-ID'] = correlationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.baseUrl}/seclore/drm/1.0/protect/hf`,
|
||||||
|
headers,
|
||||||
|
body: protectRequest,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.context.helpers.httpRequest(options);
|
||||||
|
return response as IProtectWithHotFolderResponse;
|
||||||
|
} catch (error: any) {
|
||||||
|
// Handle specific HTTP error responses
|
||||||
|
if (error.statusCode === 400) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Bad Request: ${errorResponse?.errorMessage || 'Invalid request data'}`);
|
||||||
|
} else if (error.statusCode === 401) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Unauthorized: ${errorResponse?.errorMessage || 'Invalid access token'}`);
|
||||||
|
} else if (error.statusCode === 500) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Server Error: ${errorResponse?.errorMessage || 'Internal server error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-throw other errors
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unprotects file with PS configured against the logged in Tenant in application.
|
||||||
|
*
|
||||||
|
* @param unprotectRequest - The unprotect request details with file storage ID
|
||||||
|
* @param accessToken - JWT access token for authorization
|
||||||
|
* @param correlationId - Optional request ID for logging purpose
|
||||||
|
* @returns Promise<IUnprotectResponse> - File storage ID of unprotected file
|
||||||
|
* @throws Error on bad request, authentication failure or server error
|
||||||
|
*/
|
||||||
|
async unprotect(
|
||||||
|
unprotectRequest: IUnprotectRequest,
|
||||||
|
accessToken: string,
|
||||||
|
correlationId?: string
|
||||||
|
): Promise<IUnprotectResponse> {
|
||||||
|
const headers: { [key: string]: string } = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add correlation ID if provided
|
||||||
|
if (correlationId) {
|
||||||
|
headers['X-SECLORE-CORRELATION-ID'] = correlationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.baseUrl}/seclore/drm/1.0/unprotect`,
|
||||||
|
headers,
|
||||||
|
body: unprotectRequest,
|
||||||
|
json: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.context.helpers.httpRequest(options);
|
||||||
|
return response as IUnprotectResponse;
|
||||||
|
} catch (error: any) {
|
||||||
|
// Handle specific HTTP error responses
|
||||||
|
if (error.statusCode === 400) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Bad Request: ${errorResponse?.errorMessage || 'Invalid request data'}`);
|
||||||
|
} else if (error.statusCode === 401) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Unauthorized: ${errorResponse?.errorMessage || 'Invalid access token'}`);
|
||||||
|
} else if (error.statusCode === 500) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Server Error: ${errorResponse?.errorMessage || 'Internal server error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-throw other errors
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new file to the file storage for currently logged in Tenant.
|
||||||
|
*
|
||||||
|
* @param fileBuffer - The file buffer data
|
||||||
|
* @param fileName - The name of the file
|
||||||
|
* @param accessToken - JWT access token for authorization
|
||||||
|
* @param correlationId - Optional request ID for logging purpose
|
||||||
|
* @returns Promise<IFileUploadResponse> - File storage details including file ID and metadata
|
||||||
|
* @throws Error on authentication failure, payload too large, or server error
|
||||||
|
*/
|
||||||
|
async uploadFile(
|
||||||
|
fileBuffer: Uint8Array,
|
||||||
|
fileName: string,
|
||||||
|
accessToken: string,
|
||||||
|
correlationId?: string
|
||||||
|
): Promise<IFileUploadResponse> {
|
||||||
|
const headers: { [key: string]: string } = {
|
||||||
|
'Authorization': `Bearer ${accessToken}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add correlation ID if provided
|
||||||
|
if (correlationId) {
|
||||||
|
headers['X-SECLORE-CORRELATION-ID'] = correlationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create FormData for multipart/form-data upload
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', fileBuffer, fileName);
|
||||||
|
|
||||||
|
const options: IHttpRequestOptions = {
|
||||||
|
method: 'POST',
|
||||||
|
url: `${this.baseUrl}/seclore/drm/filestorage/1.0/upload`,
|
||||||
|
headers,
|
||||||
|
body: formData,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await this.context.helpers.httpRequest(options);
|
||||||
|
return response as IFileUploadResponse;
|
||||||
|
} catch (error: any) {
|
||||||
|
// Handle specific HTTP error responses
|
||||||
|
if (error.statusCode === 401) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Unauthorized: ${errorResponse?.errorMessage || 'Invalid access token'}`);
|
||||||
|
} else if (error.statusCode === 413) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Payload Too Large: ${errorResponse?.errorMessage || 'File size exceeds limit'}`);
|
||||||
|
} else if (error.statusCode === 500) {
|
||||||
|
const errorResponse = error.response?.body as IErrorResponse;
|
||||||
|
throw new Error(`Server Error: ${errorResponse?.errorMessage || 'Internal server error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-throw other errors
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"name": "n8n-nodes-secloreprotect",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "",
|
||||||
|
"keywords": [
|
||||||
|
"n8n-community-node-package"
|
||||||
|
],
|
||||||
|
"author": {
|
||||||
|
"name": "",
|
||||||
|
"email": ""
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/seclore/n8n-nodes-secloreprotect.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "n8n-node build",
|
||||||
|
"build:watch": "tsc --watch",
|
||||||
|
"dev": "n8n-node dev",
|
||||||
|
"lint": "n8n-node lint",
|
||||||
|
"lint:fix": "n8n-node lint --fix",
|
||||||
|
"release": "n8n-node release",
|
||||||
|
"prepublishOnly": "n8n-node prerelease"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"n8n": {
|
||||||
|
"n8nNodesApiVersion": 1,
|
||||||
|
"strict": true,
|
||||||
|
"credentials": [
|
||||||
|
"dist/credentials/SecloreProtectApi.credentials.js"
|
||||||
|
],
|
||||||
|
"nodes": [
|
||||||
|
"dist/nodes/SecloreProtect/SecloreProtect.node.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@n8n/node-cli": "*",
|
||||||
|
"eslint": "9.32.0",
|
||||||
|
"prettier": "3.6.2",
|
||||||
|
"release-it": "^19.0.4",
|
||||||
|
"typescript": "5.9.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"n8n-workflow": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"strict": true,
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"target": "es2019",
|
||||||
|
"lib": ["es2019", "es2020", "es2022.error"],
|
||||||
|
"removeComments": true,
|
||||||
|
"useUnknownInCatchVariables": false,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"preserveConstEnums": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"incremental": true,
|
||||||
|
"declaration": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"outDir": "./dist/"
|
||||||
|
},
|
||||||
|
"include": ["credentials/**/*", "nodes/**/*", "nodes/**/*.json", "package.json"]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue