@unito/integration-cli 0.57.1 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.eslintrc.d.ts +6 -0
- package/dist/.eslintrc.js +9 -2
- package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/src/index.ts +1 -3
- package/dist/src/commands/activity.d.ts +2 -2
- package/dist/src/commands/activity.js +2 -2
- package/dist/src/commands/dev.d.ts +8 -4
- package/dist/src/commands/dev.js +42 -5
- package/dist/src/commands/encrypt.d.ts +1 -1
- package/dist/src/commands/encrypt.js +1 -1
- package/dist/src/commands/init.d.ts +1 -1
- package/dist/src/commands/init.js +3 -3
- package/dist/src/commands/invite.d.ts +1 -1
- package/dist/src/commands/invite.js +2 -2
- package/dist/src/commands/login.d.ts +1 -1
- package/dist/src/commands/login.js +1 -1
- package/dist/src/commands/oauth2.d.ts +3 -3
- package/dist/src/commands/oauth2.js +19 -14
- package/dist/src/commands/publish.d.ts +2 -2
- package/dist/src/commands/publish.js +12 -12
- package/dist/src/commands/test.js +32 -8
- package/dist/src/commands/upgrade.js +3 -3
- package/dist/src/errors.d.ts +8 -0
- package/dist/src/errors.js +35 -18
- package/dist/src/resources/configuration.js +0 -2
- package/dist/src/resources/credentials.d.ts +3 -0
- package/dist/src/resources/credentials.js +26 -0
- package/dist/src/resources/integrations.d.ts +1 -0
- package/dist/src/resources/integrations.js +37 -2
- package/dist/src/resources/oauth2Helper.d.ts +4 -0
- package/dist/src/resources/oauth2Helper.js +30 -0
- package/dist/src/services/integrationsPlatform.d.ts +1 -0
- package/dist/src/services/integrationsPlatform.js +5 -1
- package/dist/src/services/oauth2Helper.d.ts +78 -3
- package/dist/src/services/oauth2Helper.js +229 -29
- package/dist/test/commands/activity.test.js +12 -9
- package/dist/test/commands/dev.test.js +59 -10
- package/dist/test/commands/encrypt.test.js +6 -7
- package/dist/test/commands/init.test.js +7 -9
- package/dist/test/commands/invite.test.js +11 -11
- package/dist/test/commands/login.test.js +20 -23
- package/dist/test/commands/oauth2.test.js +6 -2
- package/dist/test/commands/publish.test.js +152 -218
- package/dist/test/commands/test.test.js +65 -13
- package/dist/test/commands/upgrade.test.js +4 -6
- package/dist/test/errors.test.js +36 -36
- package/dist/test/helpers/integrations.d.ts +26 -0
- package/dist/test/helpers/integrations.js +25 -0
- package/dist/test/helpers/styles.d.ts +1 -0
- package/dist/test/helpers/styles.js +8 -0
- package/dist/test/oauth2Helper/oauth2Helper.test.js +112 -128
- package/dist/test/resources/configuration.test.js +24 -24
- package/dist/test/resources/decryption.test.js +9 -9
- package/dist/test/resources/globalConfiguration.test.js +4 -4
- package/dist/test/resources/integrations.test.js +37 -0
- package/dist/test/resources/oauth2Helper.test.js +55 -0
- package/dist/test/services/integrationsPlatform.test.js +20 -20
- package/oclif.manifest.json +64 -9
- package/package.json +10 -14
- package/dist/integrationGenerator/errors.d.ts +0 -2
- package/dist/integrationGenerator/errors.js +0 -6
- package/dist/integrationGenerator/index.d.ts +0 -2
- package/dist/integrationGenerator/index.js +0 -5
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.dockerignore +0 -3
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.eslintrc.js +0 -74
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.nvmrc +0 -1
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.prettierignore +0 -1
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.prettierrc +0 -7
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/.unito.json +0 -1
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/Dockerfile +0 -38
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/README.md +0 -21
- package/dist/integrationGenerator/integrationBoilerplate/integrationBoilerplate/src/index.ts +0 -94
- package/dist/integrationGenerator/integrationBoilerplate/package.json +0 -43
- package/dist/integrationGenerator/integrationBoilerplate/src/logger.ts +0 -55
- package/dist/integrationGenerator/integrationBoilerplate/src/middlewares/additionalLoggingContext.ts +0 -22
- package/dist/integrationGenerator/integrationBoilerplate/src/middlewares/correlationId.ts +0 -13
- package/dist/integrationGenerator/integrationBoilerplate/src/middlewares/credentials.ts +0 -38
- package/dist/integrationGenerator/integrationBoilerplate/src/request.ts +0 -59
- package/dist/integrationGenerator/integrationBoilerplate/src/routes/index.ts +0 -11
- package/dist/integrationGenerator/integrationBoilerplate/src/routes/me.ts +0 -15
- package/dist/integrationGenerator/integrationBoilerplate/src/routes/root.ts +0 -12
- package/dist/integrationGenerator/integrationBoilerplate/tsconfig.json +0 -37
- package/dist/integrationGenerator/src/index.d.ts +0 -1
- package/dist/integrationGenerator/src/index.js +0 -5
- package/dist/integrationGenerator/src/resources/index.d.ts +0 -1
- package/dist/integrationGenerator/src/resources/index.js +0 -5
- package/dist/integrationGenerator/src/resources/integration.d.ts +0 -9
- package/dist/integrationGenerator/src/resources/integration.js +0 -60
- package/dist/integrationGenerator/test/resources/integration.test.js +0 -51
- package/dist/src/oauth2Helper/oauth2Helper.d.ts +0 -63
- package/dist/src/oauth2Helper/oauth2Helper.js +0 -235
- package/dist/src/oauth2Helper/types.d.ts +0 -22
- package/dist/src/oauth2Helper/types.js +0 -2
- package/dist/test/mocha.hooks.d.ts +0 -2
- package/dist/test/mocha.hooks.js +0 -37
- package/dist/test/services/oauth2Helper.test.js +0 -85
- /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.dockerignore +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.eslintrc.js +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.nvmrc +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.prettierignore +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.prettierrc +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/.unito.json +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/Dockerfile +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate → boilerplate}/README.md +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/package.json +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/logger.ts +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/middlewares/additionalLoggingContext.ts +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/middlewares/correlationId.ts +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/middlewares/credentials.ts +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/request.ts +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/routes/index.ts +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/routes/me.ts +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/src/routes/root.ts +0 -0
- /package/dist/{integrationGenerator/integrationBoilerplate/integrationBoilerplate → boilerplate}/tsconfig.json +0 -0
- /package/dist/{integrationGenerator/test/resources/integration.test.d.ts → test/resources/integrations.test.d.ts} +0 -0
- /package/dist/test/{services → resources}/oauth2Helper.test.d.ts +0 -0
package/dist/src/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.handleError = exports.ConfigurationInvalid = exports.EntryDecryptionError = exports.DecryptionAuthenticationError = exports.AuthenticationFailed = exports.MissingApiKey = exports.FileSizeExceeded = exports.MissingAuth2AuthorizationError = exports.InvalidRequestContentTypeError = exports.FailedToRetrieveAccessTokenError = exports.NoRefreshTokenError = exports.ConfigurationMalformed = exports.NoConfigurationFileError = exports.NoIntegrationFoundError = void 0;
|
|
3
|
+
exports.handleError = exports.ConfigurationInvalid = exports.EntryDecryptionError = exports.IntegrationAlreadyExistsError = exports.CredentialAccessDenied = exports.CredentialAuthenticationError = exports.UnsupportedContentTypeError = exports.DecryptionAuthenticationError = exports.AuthenticationFailed = exports.MissingApiKey = exports.FileSizeExceeded = exports.MissingAuth2AuthorizationError = exports.InvalidRequestContentTypeError = exports.FailedToRetrieveAccessTokenError = exports.NoRefreshTokenError = exports.ConfigurationMalformed = exports.NoConfigurationFileError = exports.NoIntegrationFoundError = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const core_1 = require("@oclif/core");
|
|
6
6
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
@@ -41,6 +41,18 @@ exports.AuthenticationFailed = AuthenticationFailed;
|
|
|
41
41
|
class DecryptionAuthenticationError extends Error {
|
|
42
42
|
}
|
|
43
43
|
exports.DecryptionAuthenticationError = DecryptionAuthenticationError;
|
|
44
|
+
class UnsupportedContentTypeError extends Error {
|
|
45
|
+
}
|
|
46
|
+
exports.UnsupportedContentTypeError = UnsupportedContentTypeError;
|
|
47
|
+
class CredentialAuthenticationError extends Error {
|
|
48
|
+
}
|
|
49
|
+
exports.CredentialAuthenticationError = CredentialAuthenticationError;
|
|
50
|
+
class CredentialAccessDenied extends Error {
|
|
51
|
+
}
|
|
52
|
+
exports.CredentialAccessDenied = CredentialAccessDenied;
|
|
53
|
+
class IntegrationAlreadyExistsError extends Error {
|
|
54
|
+
}
|
|
55
|
+
exports.IntegrationAlreadyExistsError = IntegrationAlreadyExistsError;
|
|
44
56
|
class EntryDecryptionError extends Error {
|
|
45
57
|
key;
|
|
46
58
|
value;
|
|
@@ -68,45 +80,37 @@ function handleError(command, error) {
|
|
|
68
80
|
if (core_1.ux.action.running) {
|
|
69
81
|
core_1.ux.action.stop(chalk_1.default.redBright('failed'));
|
|
70
82
|
}
|
|
71
|
-
let
|
|
83
|
+
let unhandled = false;
|
|
72
84
|
if (error instanceof NoIntegrationFoundError) {
|
|
73
85
|
command.logToStderr(chalk_1.default.redBright('Your directory does not seem to contain an integration :('));
|
|
74
86
|
command.logToStderr(`Make sure you are in the right directory and that you have a ${chalk_1.default.yellowBright(configuration_1.DEFAULT_CONFIGURATION_NAME)} file.`);
|
|
75
|
-
handled = true;
|
|
76
87
|
}
|
|
77
88
|
else if (error instanceof NoConfigurationFileError) {
|
|
78
89
|
command.logToStderr(chalk_1.default.redBright('This command requires a configuration file for your integration :('));
|
|
79
90
|
command.logToStderr(`This file should be located at ${chalk_1.default.yellowBright(path_1.default.relative(process.cwd(), (0, configuration_1.getConfigurationPath)()))}.`);
|
|
80
|
-
handled = true;
|
|
81
91
|
}
|
|
82
92
|
else if (error instanceof ConfigurationMalformed) {
|
|
83
93
|
command.logToStderr(chalk_1.default.redBright(`Your ${chalk_1.default.yellowBright(configuration_1.DEFAULT_CONFIGURATION_NAME)} was found but its not a valid JSON file!`));
|
|
84
|
-
handled = true;
|
|
85
94
|
}
|
|
86
95
|
else if (error instanceof ConfigurationInvalid) {
|
|
87
96
|
command.logToStderr(chalk_1.default.redBright(`Your ${chalk_1.default.yellowBright(configuration_1.DEFAULT_CONFIGURATION_NAME)} is invalid!`));
|
|
88
97
|
command.logToStderr();
|
|
89
98
|
command.logToStderr(error.prettyDetails);
|
|
90
|
-
handled = true;
|
|
91
99
|
}
|
|
92
100
|
else if (error instanceof NoRefreshTokenError) {
|
|
93
101
|
command.logToStderr(chalk_1.default.redBright('No refresh token found in your configuration file'));
|
|
94
|
-
handled = true;
|
|
95
102
|
}
|
|
96
103
|
else if (error instanceof FailedToRetrieveAccessTokenError) {
|
|
97
104
|
command.logToStderr(chalk_1.default.redBright('Failed to retrieve access token'));
|
|
98
105
|
command.logToStderr();
|
|
99
106
|
command.logToStderr(error.message);
|
|
100
|
-
handled = true;
|
|
101
107
|
}
|
|
102
108
|
else if (error instanceof InvalidRequestContentTypeError) {
|
|
103
109
|
command.logToStderr(chalk_1.default.redBright('Invalid request content type'));
|
|
104
|
-
handled = true;
|
|
105
110
|
command.logToStderr();
|
|
106
111
|
command.logToStderr(error.message);
|
|
107
112
|
}
|
|
108
113
|
else if (error instanceof integrationsPlatform_1.HttpError) {
|
|
109
|
-
handled = true;
|
|
110
114
|
command.logToStderr();
|
|
111
115
|
command.logToStderr((0, json_colorizer_1.default)(JSON.stringify(error.data, null, 2)));
|
|
112
116
|
}
|
|
@@ -114,13 +118,11 @@ function handleError(command, error) {
|
|
|
114
118
|
command.logToStderr();
|
|
115
119
|
command.logToStderr(chalk_1.default.redBright('Your API key is not set!'));
|
|
116
120
|
command.logToStderr(`Make sure to run the ${chalk_1.default.yellowBright('login')} command first.`);
|
|
117
|
-
handled = true;
|
|
118
121
|
}
|
|
119
122
|
else if (error instanceof AuthenticationFailed) {
|
|
120
123
|
command.logToStderr();
|
|
121
124
|
command.logToStderr(chalk_1.default.redBright('This command requires that you are logged to Unito!'));
|
|
122
125
|
command.logToStderr(`Make sure to run the ${chalk_1.default.yellowBright('login')} command first.`);
|
|
123
|
-
handled = true;
|
|
124
126
|
}
|
|
125
127
|
else if (error instanceof DecryptionAuthenticationError) {
|
|
126
128
|
command.logToStderr();
|
|
@@ -128,7 +130,6 @@ function handleError(command, error) {
|
|
|
128
130
|
command.logToStderr('Your configuration contains secrets (i.e. in top-level secrets, in test accounts, etc.).');
|
|
129
131
|
command.logToStderr('To decrypt those secrets locally, you must authenticate to Unito.');
|
|
130
132
|
command.logToStderr(`Make sure to run the ${chalk_1.default.yellowBright('login')} command first.`);
|
|
131
|
-
handled = true;
|
|
132
133
|
}
|
|
133
134
|
else if (error instanceof EntryDecryptionError) {
|
|
134
135
|
command.logToStderr();
|
|
@@ -140,15 +141,31 @@ function handleError(command, error) {
|
|
|
140
141
|
command.logToStderr(`1. The integration was deployed once with the ${chalk_1.default.yellowBright('publish')} command.`);
|
|
141
142
|
command.logToStderr('2. You have access to the integration.');
|
|
142
143
|
command.logToStderr(`3. The secret was encrypted for the ${chalk_1.default.yellowBright(error.environment)} environment.`);
|
|
143
|
-
handled = true;
|
|
144
144
|
}
|
|
145
145
|
else if (error instanceof MissingAuth2AuthorizationError) {
|
|
146
146
|
command.logToStderr();
|
|
147
147
|
command.logToStderr(chalk_1.default.redBright(`No Oauth2 authorization found in your configuration file`));
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
command.logToStderr('See https://dev.unito.io/docs/connectors/configuration/authorizations#oauth-2 for more information on how to configure Oauth2');
|
|
149
|
+
}
|
|
150
|
+
else if (error instanceof CredentialAuthenticationError) {
|
|
151
|
+
command.logToStderr();
|
|
152
|
+
command.logToStderr(chalk_1.default.redBright('The credential cannot be obtained!'));
|
|
153
|
+
command.logToStderr('To obtain information on the credential, you must authenticate to Unito.');
|
|
154
|
+
command.logToStderr(`Make sure to run the ${chalk_1.default.yellowBright('login')} command first.`);
|
|
155
|
+
}
|
|
156
|
+
else if (error instanceof CredentialAccessDenied) {
|
|
157
|
+
command.logToStderr();
|
|
158
|
+
command.logToStderr(chalk_1.default.redBright('The credential cannot be obtained!'));
|
|
159
|
+
command.logToStderr("You don't have access to this credential or the credential doesn't exist.");
|
|
160
|
+
}
|
|
161
|
+
else if (error instanceof IntegrationAlreadyExistsError) {
|
|
162
|
+
command.logToStderr();
|
|
163
|
+
command.logToStderr(chalk_1.default.redBright(`The integration already exists in this folder.`));
|
|
164
|
+
command.logToStderr(`Make sure to provide a unique name for your integration.`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
unhandled = true;
|
|
151
168
|
}
|
|
152
|
-
return
|
|
169
|
+
return !unhandled;
|
|
153
170
|
}
|
|
154
171
|
exports.handleError = handleError;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.writeTestAccount = exports.writeConfiguration = exports.getConfiguration = exports.getConfigurationPath = exports.ENCRYPTION_PREFIX = exports.DEFAULT_CONFIGURATION_NAME = exports.CredentialScope = exports.CrawlMode = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const core_1 = require("@oclif/core");
|
|
6
5
|
const fs = tslib_1.__importStar(require("fs"));
|
|
7
6
|
const ajv_1 = tslib_1.__importDefault(require("ajv"));
|
|
8
7
|
const ajv_formats_1 = tslib_1.__importDefault(require("ajv-formats"));
|
|
@@ -48,7 +47,6 @@ async function getConfiguration(environment, customConfigPath) {
|
|
|
48
47
|
const configurationPath = customConfigPath
|
|
49
48
|
? `${process.cwd()}${customConfigPath.startsWith('/') ? customConfigPath : `/${customConfigPath}`}`
|
|
50
49
|
: getConfigurationPath(environment);
|
|
51
|
-
core_1.ux.log(`Loading ${configurationPath} configuration file`);
|
|
52
50
|
try {
|
|
53
51
|
fileContent = await fs.promises.readFile(configurationPath, 'utf-8');
|
|
54
52
|
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import * as GlobalConfiguration from './globalConfiguration';
|
|
2
|
+
import { Credential } from '../services/integrationsPlatform';
|
|
3
|
+
export declare function fetchCredential(environment: GlobalConfiguration.Environment, configDir: string, credentialId: number): Promise<Credential>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchCredential = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const errors_1 = require("../errors");
|
|
6
|
+
const GlobalConfiguration = tslib_1.__importStar(require("./globalConfiguration"));
|
|
7
|
+
const integrationsPlatform_1 = require("./integrationsPlatform");
|
|
8
|
+
const integrationsPlatform_2 = require("../services/integrationsPlatform");
|
|
9
|
+
async function fetchCredential(environment, configDir, credentialId) {
|
|
10
|
+
const globalConfiguration = await GlobalConfiguration.read(configDir);
|
|
11
|
+
try {
|
|
12
|
+
await (0, integrationsPlatform_1.validateAuthenticated)(globalConfiguration, environment);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
throw new errors_1.CredentialAuthenticationError();
|
|
16
|
+
}
|
|
17
|
+
let credential;
|
|
18
|
+
try {
|
|
19
|
+
credential = await (0, integrationsPlatform_2.getCredential)(credentialId);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
throw new errors_1.CredentialAccessDenied();
|
|
23
|
+
}
|
|
24
|
+
return credential;
|
|
25
|
+
}
|
|
26
|
+
exports.fetchCredential = fetchCredential;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isIntegrationDirectory = exports.validateIsIntegrationDirectory = void 0;
|
|
3
|
+
exports.copyBoilerplate = exports.isIntegrationDirectory = exports.validateIsIntegrationDirectory = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const path_1 = tslib_1.__importDefault(require("path"));
|
|
5
6
|
const fs_1 = tslib_1.__importDefault(require("fs"));
|
|
6
7
|
const errors_1 = require("../errors");
|
|
8
|
+
const errors_2 = require("../errors");
|
|
7
9
|
const configuration_1 = require("./configuration");
|
|
8
10
|
function validateIsIntegrationDirectory() {
|
|
9
11
|
if (!isIntegrationDirectory()) {
|
|
10
|
-
throw new
|
|
12
|
+
throw new errors_2.NoIntegrationFoundError();
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
exports.validateIsIntegrationDirectory = validateIsIntegrationDirectory;
|
|
@@ -15,3 +17,36 @@ function isIntegrationDirectory() {
|
|
|
15
17
|
return fs_1.default.existsSync((0, configuration_1.getConfigurationPath)());
|
|
16
18
|
}
|
|
17
19
|
exports.isIntegrationDirectory = isIntegrationDirectory;
|
|
20
|
+
async function copyBoilerplate(integrationName, destinationPath) {
|
|
21
|
+
const sourcePath = path_1.default.join(__dirname, `../../boilerplate`);
|
|
22
|
+
const targetPath = `${destinationPath}/${integrationName.toLowerCase().replace(/ /g, '_')}`;
|
|
23
|
+
if (fs_1.default.existsSync(targetPath)) {
|
|
24
|
+
throw new errors_1.IntegrationAlreadyExistsError();
|
|
25
|
+
}
|
|
26
|
+
await fs_1.default.promises.mkdir(targetPath, { recursive: true });
|
|
27
|
+
await copyFilesAndFolders(sourcePath, targetPath, ['node_modules', 'dist']);
|
|
28
|
+
// The .npmrc file is created here because
|
|
29
|
+
// it will be excluded during the CLI package's publishing process by npm.
|
|
30
|
+
const npmrcContent = ['engine-strict=true', 'strict-ssl=true'].join('\n');
|
|
31
|
+
await fs_1.default.promises.writeFile(path_1.default.join(targetPath, '.npmrc'), npmrcContent);
|
|
32
|
+
return targetPath;
|
|
33
|
+
}
|
|
34
|
+
exports.copyBoilerplate = copyBoilerplate;
|
|
35
|
+
async function copyFilesAndFolders(source, destination, excludedFolders) {
|
|
36
|
+
const files = await fs_1.default.promises.readdir(source);
|
|
37
|
+
for (const file of files) {
|
|
38
|
+
if (excludedFolders.includes(file)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const sourcePath = path_1.default.join(source, file);
|
|
42
|
+
const targetPath = path_1.default.join(destination, file);
|
|
43
|
+
const stats = await fs_1.default.promises.stat(sourcePath);
|
|
44
|
+
if (stats.isFile()) {
|
|
45
|
+
await fs_1.default.promises.copyFile(sourcePath, targetPath);
|
|
46
|
+
}
|
|
47
|
+
else if (stats.isDirectory()) {
|
|
48
|
+
await fs_1.default.promises.mkdir(targetPath);
|
|
49
|
+
await copyFilesAndFolders(sourcePath, targetPath, excludedFolders);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Oauth2Response, Oauth2Payload } from '../services/oauth2Helper';
|
|
2
|
+
import { Environment } from './globalConfiguration';
|
|
3
|
+
export declare function performOAuth2Flow(applicationCredentials: Oauth2Payload, environment?: Environment): Promise<Oauth2Response>;
|
|
4
|
+
export declare function updateToken(applicationCredentials: Oauth2Payload, refreshToken: string): Promise<Oauth2Response>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateToken = exports.performOAuth2Flow = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const oauth2Helper_1 = tslib_1.__importDefault(require("../services/oauth2Helper"));
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const globalConfiguration_1 = require("./globalConfiguration");
|
|
8
|
+
async function performOAuth2Flow(applicationCredentials, environment = globalConfiguration_1.Environment.Production) {
|
|
9
|
+
const oauthHelper = new oauth2Helper_1.default(applicationCredentials, environment);
|
|
10
|
+
const serverUrl = await oauthHelper.startServer();
|
|
11
|
+
const healthCheck = await fetch(`${serverUrl}/health`);
|
|
12
|
+
if (healthCheck.status !== 200) {
|
|
13
|
+
throw new Error('OAuthServer did not start');
|
|
14
|
+
}
|
|
15
|
+
await oauthHelper.authorize();
|
|
16
|
+
const oauth2Response = await oauthHelper.callbackIsDone();
|
|
17
|
+
await oauthHelper.stopServer();
|
|
18
|
+
if (!oauth2Response.accessToken) {
|
|
19
|
+
throw new errors_1.FailedToRetrieveAccessTokenError('Access token was not returned');
|
|
20
|
+
}
|
|
21
|
+
return oauth2Response;
|
|
22
|
+
}
|
|
23
|
+
exports.performOAuth2Flow = performOAuth2Flow;
|
|
24
|
+
/* istanbul ignore next */
|
|
25
|
+
// No point to test this function as it is just a wrapper around OAuth2Helper
|
|
26
|
+
async function updateToken(applicationCredentials, refreshToken) {
|
|
27
|
+
const oauthHelper = new oauth2Helper_1.default(applicationCredentials);
|
|
28
|
+
return oauthHelper.updateToken(refreshToken);
|
|
29
|
+
}
|
|
30
|
+
exports.updateToken = updateToken;
|
|
@@ -38,3 +38,4 @@ export declare function getIntegrationEvents(integrationId: number, options?: {
|
|
|
38
38
|
limit?: number;
|
|
39
39
|
}): Promise<IntegrationEvent[]>;
|
|
40
40
|
export declare function updateIntegration(integrationId: number, configuration: Configuration): Promise<Integration>;
|
|
41
|
+
export declare function getCredential(credentialId: number): Promise<Credential>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.updateIntegration = exports.getIntegrationEvents = exports.inviteUserToIntegration = exports.createIntegration = exports.publishIntegration = exports.getIntegrations = exports.getIntegrationByName = exports.getIntegration = exports.reencryptData = exports.decryptData = exports.encryptData = exports.getProfile = exports.setApiKey = exports.getApiKey = exports.setEnvironment = exports.Servers = exports.HttpError = void 0;
|
|
3
|
+
exports.getCredential = exports.updateIntegration = exports.getIntegrationEvents = exports.inviteUserToIntegration = exports.createIntegration = exports.publishIntegration = exports.getIntegrations = exports.getIntegrationByName = exports.getIntegration = exports.reencryptData = exports.decryptData = exports.encryptData = exports.getProfile = exports.setApiKey = exports.getApiKey = exports.setEnvironment = exports.Servers = exports.HttpError = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const fs = tslib_1.__importStar(require("fs"));
|
|
6
6
|
const integrations_platform_client_1 = tslib_1.__importDefault(require("@unito/integrations-platform-client"));
|
|
@@ -153,3 +153,7 @@ async function updateIntegration(integrationId, configuration) {
|
|
|
153
153
|
});
|
|
154
154
|
}
|
|
155
155
|
exports.updateIntegration = updateIntegration;
|
|
156
|
+
async function getCredential(credentialId) {
|
|
157
|
+
return integrations_platform_client_1.default.getCredentialById(credentialId);
|
|
158
|
+
}
|
|
159
|
+
exports.getCredential = getCredential;
|
|
@@ -1,3 +1,78 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as openUrl from 'openurl';
|
|
2
|
+
import { Oauth2 } from '../configurationTypes';
|
|
3
|
+
import { Environment } from '../resources/globalConfiguration';
|
|
4
|
+
export declare const open: typeof openUrl;
|
|
5
|
+
export declare const HTML_ERROR_MSG = "<!doctype html><head><title>Unito</title></head><body style=\"text-align:center\"> An unknown error occured </body>";
|
|
6
|
+
export declare const HTML_SUCCESS_MSG = "<!doctype html><head><title>Unito</title></head><body style=\"text-align:center\"> Redirected to the CLI successfully </body>";
|
|
7
|
+
export interface Oauth2Credentials {
|
|
8
|
+
clientId: string;
|
|
9
|
+
clientSecret: string;
|
|
10
|
+
}
|
|
11
|
+
export interface AuthorizePayload extends Oauth2Credentials {
|
|
12
|
+
providerAuthorizationUrl: string;
|
|
13
|
+
scopes?: string;
|
|
14
|
+
providerAccessTokenUrl: string;
|
|
15
|
+
}
|
|
16
|
+
export interface CallbackPayload {
|
|
17
|
+
code: string;
|
|
18
|
+
}
|
|
19
|
+
export interface Oauth2Response {
|
|
20
|
+
accessToken: string;
|
|
21
|
+
refreshToken?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface TokenPayload extends Oauth2Credentials {
|
|
24
|
+
providerTokenUrl: string;
|
|
25
|
+
code: string;
|
|
26
|
+
}
|
|
27
|
+
export type Oauth2Payload = Oauth2;
|
|
28
|
+
declare class OAuth2Helper {
|
|
29
|
+
private environment;
|
|
30
|
+
private server;
|
|
31
|
+
private clientId;
|
|
32
|
+
private clientSecret;
|
|
33
|
+
private providerAuthorizationUrl;
|
|
34
|
+
private tokenUrl;
|
|
35
|
+
private scopes;
|
|
36
|
+
private grantType;
|
|
37
|
+
private requestContentType;
|
|
38
|
+
private oauth2Response;
|
|
39
|
+
private serverUrl;
|
|
40
|
+
private tokenRequestParameters;
|
|
41
|
+
private refreshRequestParameters;
|
|
42
|
+
/**
|
|
43
|
+
* Constructs an instance of OAuthHelper.
|
|
44
|
+
* @param clientId The client ID for your OAuth application.
|
|
45
|
+
* @param clientSecret The client secret for your OAuth application.
|
|
46
|
+
* @param authorizationUrl The URL for the authorization endpoint of the provider.
|
|
47
|
+
* @param scopes The scopes required for the OAuth authorization.
|
|
48
|
+
* @param providerTokenUrl The URL for the token endpoint of the provider.
|
|
49
|
+
*/
|
|
50
|
+
constructor(authorizationInfo: Oauth2Payload, environment?: Environment);
|
|
51
|
+
/**
|
|
52
|
+
* Initiate the authorization flow and redirects the user to the provider's authorization page.
|
|
53
|
+
*/
|
|
54
|
+
authorize(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Handles the callback request from the provider and stores the authorization code.
|
|
57
|
+
* @param req The express Request object.
|
|
58
|
+
* @param res The express Response object.
|
|
59
|
+
*/
|
|
60
|
+
private handleCallback;
|
|
61
|
+
/**
|
|
62
|
+
* Waits for the authorization code to be set.
|
|
63
|
+
* @returns A promise that resolves when the code is set.
|
|
64
|
+
*/
|
|
65
|
+
callbackIsDone(): Promise<Oauth2Response>;
|
|
66
|
+
private encodeBody;
|
|
67
|
+
updateToken(refreshToken: string): Promise<Oauth2Response>;
|
|
68
|
+
/**
|
|
69
|
+
* Starts the Express server for handling OAuth callbacks.
|
|
70
|
+
* @returns The URL of the server.
|
|
71
|
+
*/
|
|
72
|
+
startServer(): Promise<string>;
|
|
73
|
+
/**
|
|
74
|
+
* Stops the Express server.
|
|
75
|
+
*/
|
|
76
|
+
stopServer(): Promise<void>;
|
|
77
|
+
}
|
|
78
|
+
export default OAuth2Helper;
|
|
@@ -1,34 +1,234 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.HTML_SUCCESS_MSG = exports.HTML_ERROR_MSG = exports.open = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const
|
|
5
|
+
const express_1 = tslib_1.__importDefault(require("express"));
|
|
6
|
+
const cors_1 = tslib_1.__importDefault(require("cors"));
|
|
7
|
+
const openUrl = tslib_1.__importStar(require("openurl"));
|
|
8
|
+
const ngrok_1 = tslib_1.__importDefault(require("ngrok"));
|
|
9
|
+
const IntegrationsPlatformClient = tslib_1.__importStar(require("./integrationsPlatform"));
|
|
10
|
+
const configurationTypes_1 = require("../configurationTypes");
|
|
6
11
|
const errors_1 = require("../errors");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
12
|
+
const globalConfiguration_1 = require("../resources/globalConfiguration");
|
|
13
|
+
// It allows to stub openUrl library in the test
|
|
14
|
+
exports.open = openUrl;
|
|
15
|
+
exports.HTML_ERROR_MSG = `<!doctype html><head><title>Unito</title></head><body style="text-align:center"> An unknown error occured </body>`;
|
|
16
|
+
exports.HTML_SUCCESS_MSG = `<!doctype html><head><title>Unito</title></head><body style="text-align:center"> Redirected to the CLI successfully </body>`;
|
|
17
|
+
class OAuth2Helper {
|
|
18
|
+
environment;
|
|
19
|
+
server = null;
|
|
20
|
+
clientId;
|
|
21
|
+
clientSecret;
|
|
22
|
+
providerAuthorizationUrl;
|
|
23
|
+
tokenUrl;
|
|
24
|
+
scopes;
|
|
25
|
+
grantType;
|
|
26
|
+
requestContentType;
|
|
27
|
+
oauth2Response;
|
|
28
|
+
serverUrl = '';
|
|
29
|
+
tokenRequestParameters;
|
|
30
|
+
refreshRequestParameters;
|
|
31
|
+
/**
|
|
32
|
+
* Constructs an instance of OAuthHelper.
|
|
33
|
+
* @param clientId The client ID for your OAuth application.
|
|
34
|
+
* @param clientSecret The client secret for your OAuth application.
|
|
35
|
+
* @param authorizationUrl The URL for the authorization endpoint of the provider.
|
|
36
|
+
* @param scopes The scopes required for the OAuth authorization.
|
|
37
|
+
* @param providerTokenUrl The URL for the token endpoint of the provider.
|
|
38
|
+
*/
|
|
39
|
+
constructor(authorizationInfo, environment = globalConfiguration_1.Environment.Production) {
|
|
40
|
+
const { clientId, clientSecret, authorizationUrl, scopes, tokenUrl, grantType, requestContentType, refreshRequestParameters, tokenRequestParameters, } = authorizationInfo;
|
|
41
|
+
this.startServer = this.startServer.bind(this);
|
|
42
|
+
this.stopServer = this.stopServer.bind(this);
|
|
43
|
+
this.handleCallback = this.handleCallback.bind(this);
|
|
44
|
+
this.clientId = clientId;
|
|
45
|
+
this.clientSecret = clientSecret;
|
|
46
|
+
this.providerAuthorizationUrl = authorizationUrl;
|
|
47
|
+
this.scopes = scopes.map(scope => scope.name);
|
|
48
|
+
this.tokenUrl = tokenUrl;
|
|
49
|
+
this.grantType = grantType ?? configurationTypes_1.GrantType.AUTHORIZATION_CODE;
|
|
50
|
+
this.requestContentType = requestContentType ?? configurationTypes_1.RequestContentType.URL_ENCODED;
|
|
51
|
+
this.tokenRequestParameters = tokenRequestParameters;
|
|
52
|
+
this.refreshRequestParameters = refreshRequestParameters;
|
|
53
|
+
this.environment = environment;
|
|
54
|
+
if (!Object.values(configurationTypes_1.RequestContentType).includes(this.requestContentType)) {
|
|
55
|
+
throw new errors_1.UnsupportedContentTypeError(`Request content type not supported: ${this.requestContentType}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Initiate the authorization flow and redirects the user to the provider's authorization page.
|
|
60
|
+
*/
|
|
61
|
+
async authorize() {
|
|
62
|
+
if (!this.providerAuthorizationUrl) {
|
|
63
|
+
throw new errors_1.InvalidRequestContentTypeError('authorizationUrl must be defined in .unito.json');
|
|
64
|
+
}
|
|
65
|
+
const authUrl = new URL(this.providerAuthorizationUrl);
|
|
66
|
+
const params = new URLSearchParams(authUrl.search);
|
|
67
|
+
if (this.clientId) {
|
|
68
|
+
params.set('client_id', this.clientId);
|
|
69
|
+
}
|
|
70
|
+
params.set('redirect_uri', `${IntegrationsPlatformClient.Servers[this.environment]}/credentials/new/oauth2/callback-cli`);
|
|
71
|
+
const state = Buffer.from(JSON.stringify({
|
|
72
|
+
cliCallbackUrl: `${this.serverUrl}/oauth2/callback`,
|
|
73
|
+
})).toString('base64');
|
|
74
|
+
params.set('state', state);
|
|
75
|
+
if (this.scopes) {
|
|
76
|
+
params.set('scope', this.scopes.join(' '));
|
|
77
|
+
}
|
|
78
|
+
params.set('response_type', 'code');
|
|
79
|
+
authUrl.search = params.toString();
|
|
80
|
+
exports.open.open(authUrl.toString());
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Handles the callback request from the provider and stores the authorization code.
|
|
84
|
+
* @param req The express Request object.
|
|
85
|
+
* @param res The express Response object.
|
|
86
|
+
*/
|
|
87
|
+
async handleCallback(req, res) {
|
|
88
|
+
// Authorization Response: https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2
|
|
89
|
+
// const state = req.state as string;
|
|
90
|
+
// Error response: https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2.1
|
|
91
|
+
const error = req.query.error;
|
|
92
|
+
if (error) {
|
|
93
|
+
res.setHeader('Content-Type', 'text/html').send(exports.HTML_ERROR_MSG);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const code = req.query.code;
|
|
97
|
+
const bodyData = {
|
|
98
|
+
code,
|
|
99
|
+
grant_type: this.grantType,
|
|
100
|
+
redirect_uri: `${IntegrationsPlatformClient.Servers[this.environment]}/credentials/new/oauth2/callback-cli`,
|
|
101
|
+
};
|
|
102
|
+
if (this.clientId) {
|
|
103
|
+
bodyData.client_id = this.clientId;
|
|
104
|
+
}
|
|
105
|
+
if (this.clientSecret) {
|
|
106
|
+
bodyData.client_secret = this.clientSecret;
|
|
107
|
+
}
|
|
108
|
+
const fetchOptions = {
|
|
109
|
+
headers: {
|
|
110
|
+
'Content-type': this.requestContentType,
|
|
111
|
+
...(this.tokenRequestParameters?.header ?? {}),
|
|
112
|
+
},
|
|
113
|
+
body: this.encodeBody(bodyData, this.requestContentType),
|
|
114
|
+
method: 'POST',
|
|
115
|
+
};
|
|
116
|
+
try {
|
|
117
|
+
const fetchResult = await fetch(this.tokenUrl, fetchOptions);
|
|
118
|
+
if (fetchResult.status !== 200) {
|
|
119
|
+
res.setHeader('Content-Type', 'text/html');
|
|
120
|
+
res.send(exports.HTML_ERROR_MSG);
|
|
121
|
+
}
|
|
122
|
+
const response = await fetchResult.json();
|
|
123
|
+
this.oauth2Response = {
|
|
124
|
+
accessToken: response.access_token,
|
|
125
|
+
refreshToken: response.refresh_token,
|
|
126
|
+
};
|
|
127
|
+
res.setHeader('Content-Type', 'text/html');
|
|
128
|
+
res.send(exports.HTML_SUCCESS_MSG);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
res.setHeader('Content-Type', 'text/html');
|
|
132
|
+
res.send(exports.HTML_ERROR_MSG);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Waits for the authorization code to be set.
|
|
137
|
+
* @returns A promise that resolves when the code is set.
|
|
138
|
+
*/
|
|
139
|
+
/* istanbul ignore next */
|
|
140
|
+
async callbackIsDone() {
|
|
141
|
+
if (this.oauth2Response) {
|
|
142
|
+
return this.oauth2Response;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
return new Promise(resolve => {
|
|
146
|
+
const interval = setInterval(() => {
|
|
147
|
+
if (this.oauth2Response) {
|
|
148
|
+
clearInterval(interval);
|
|
149
|
+
resolve(this.oauth2Response);
|
|
150
|
+
}
|
|
151
|
+
}, 100);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
encodeBody(bodyData, contentType) {
|
|
156
|
+
switch (contentType) {
|
|
157
|
+
case configurationTypes_1.RequestContentType.URL_ENCODED:
|
|
158
|
+
return new URLSearchParams(bodyData).toString();
|
|
159
|
+
case configurationTypes_1.RequestContentType.JSON:
|
|
160
|
+
return JSON.stringify(bodyData);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
async updateToken(refreshToken) {
|
|
164
|
+
if (!Object.values(configurationTypes_1.RequestContentType).includes(this.requestContentType)) {
|
|
165
|
+
throw new errors_1.InvalidRequestContentTypeError(`Request content type not supported: ${this.requestContentType}`);
|
|
166
|
+
}
|
|
167
|
+
const bodyData = {
|
|
168
|
+
grant_type: 'refresh_token',
|
|
169
|
+
refresh_token: refreshToken,
|
|
170
|
+
};
|
|
171
|
+
if (this.clientId) {
|
|
172
|
+
bodyData.client_id = this.clientId;
|
|
173
|
+
}
|
|
174
|
+
if (this.clientSecret) {
|
|
175
|
+
bodyData.client_secret = this.clientSecret;
|
|
176
|
+
}
|
|
177
|
+
const fetchOptions = {
|
|
178
|
+
headers: {
|
|
179
|
+
'Content-type': this.requestContentType,
|
|
180
|
+
...(this.refreshRequestParameters?.header ?? {}),
|
|
181
|
+
},
|
|
182
|
+
body: this.encodeBody(bodyData, this.requestContentType),
|
|
183
|
+
method: 'POST',
|
|
184
|
+
};
|
|
185
|
+
try {
|
|
186
|
+
const fetchResult = await fetch(this.tokenUrl, fetchOptions);
|
|
187
|
+
if (fetchResult.status !== 200) {
|
|
188
|
+
throw new errors_1.FailedToRetrieveAccessTokenError(await fetchResult.text());
|
|
189
|
+
}
|
|
190
|
+
const response = await fetchResult.json();
|
|
191
|
+
const credentialsInfo = {
|
|
192
|
+
accessToken: response.access_token,
|
|
193
|
+
refreshToken: response.refresh_token,
|
|
194
|
+
};
|
|
195
|
+
return credentialsInfo;
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
throw new errors_1.FailedToRetrieveAccessTokenError(JSON.stringify(error));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Starts the Express server for handling OAuth callbacks.
|
|
203
|
+
* @returns The URL of the server.
|
|
204
|
+
*/
|
|
205
|
+
/* istanbul ignore next */
|
|
206
|
+
async startServer() {
|
|
207
|
+
const app = (0, express_1.default)();
|
|
208
|
+
const PORT = process.env.OAUTH2_PORT ?? 9002;
|
|
209
|
+
this.serverUrl = await ngrok_1.default.connect(Number(PORT));
|
|
210
|
+
app.use((0, cors_1.default)({ credentials: true, origin: true }));
|
|
211
|
+
app.use(express_1.default.json());
|
|
212
|
+
app.get('/health', (_req, res) => {
|
|
213
|
+
res.send('pong');
|
|
214
|
+
});
|
|
215
|
+
app.get('/oauth2/callback', this.handleCallback);
|
|
216
|
+
this.server = app.listen(PORT, () => {
|
|
217
|
+
console.log(`Listening at port ${PORT}`);
|
|
218
|
+
});
|
|
219
|
+
return this.serverUrl;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Stops the Express server.
|
|
223
|
+
*/
|
|
224
|
+
/* istanbul ignore next */
|
|
225
|
+
async stopServer() {
|
|
226
|
+
if (this.server) {
|
|
227
|
+
await ngrok_1.default.kill();
|
|
228
|
+
this.server.close(() => {
|
|
229
|
+
console.log('Server has stopped');
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
33
233
|
}
|
|
34
|
-
exports.
|
|
234
|
+
exports.default = OAuth2Helper;
|