@crowdin/app-project-module 0.59.0 → 0.60.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/out/modules/integration/handlers/main.js +6 -3
- package/out/modules/integration/handlers/oauth-login.js +20 -10
- package/out/modules/integration/handlers/oauth-polling.d.ts +5 -0
- package/out/modules/integration/handlers/oauth-polling.js +32 -0
- package/out/modules/integration/handlers/oauth-url.js +1 -3
- package/out/modules/integration/index.js +4 -0
- package/out/modules/integration/types.d.ts +5 -0
- package/out/modules/integration/util/defaults.d.ts +7 -1
- package/out/modules/integration/util/defaults.js +26 -10
- package/out/views/login.handlebars +35 -0
- package/out/views/oauth.handlebars +8 -1
- package/package.json +1 -1
|
@@ -31,10 +31,13 @@ function handle(config, integration) {
|
|
|
31
31
|
options.loginFields = (_a = integration.loginForm) === null || _a === void 0 ? void 0 : _a.fields;
|
|
32
32
|
if (integration.oauthLogin) {
|
|
33
33
|
options.loginFields = integration.oauthLogin.loginFields || [];
|
|
34
|
-
options.oauthUrl =
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
options.oauthUrl = (0, defaults_1.constructOauthUrl)({
|
|
35
|
+
config,
|
|
36
|
+
integration,
|
|
37
|
+
clientId: req.crowdinContext.clientId,
|
|
38
|
+
});
|
|
37
39
|
options.oauthLogin = true;
|
|
40
|
+
options.oauthMode = integration.oauthLogin.mode;
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
else if (integration.getConfiguration) {
|
|
@@ -16,14 +16,21 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
16
16
|
const util_1 = require("../../../util");
|
|
17
17
|
const defaults_1 = require("../util/defaults");
|
|
18
18
|
const logger_1 = require("../../../util/logger");
|
|
19
|
+
const storage_1 = require("../../../storage");
|
|
19
20
|
function handle(config, integration) {
|
|
20
21
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
21
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
22
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
22
23
|
const message = {
|
|
23
24
|
uid: 'oauth_popup',
|
|
24
25
|
};
|
|
25
26
|
const code = req.query[((_b = (_a = integration.oauthLogin) === null || _a === void 0 ? void 0 : _a.fieldsMapping) === null || _b === void 0 ? void 0 : _b.code) || 'code'];
|
|
27
|
+
const state = ((_c = integration.oauthLogin) === null || _c === void 0 ? void 0 : _c.mode) === 'polling'
|
|
28
|
+
? req.query[((_e = (_d = integration.oauthLogin) === null || _d === void 0 ? void 0 : _d.fieldsMapping) === null || _e === void 0 ? void 0 : _e.state) || 'state']
|
|
29
|
+
: undefined;
|
|
26
30
|
(0, logger_1.log)(`Received request from OAuth login callback. Code ${code}`);
|
|
31
|
+
if (state) {
|
|
32
|
+
(0, logger_1.log)(`Received request from OAuth login callback. State ${state}`);
|
|
33
|
+
}
|
|
27
34
|
try {
|
|
28
35
|
const oauthLogin = integration.oauthLogin;
|
|
29
36
|
let credentials;
|
|
@@ -34,26 +41,29 @@ function handle(config, integration) {
|
|
|
34
41
|
else {
|
|
35
42
|
const request = {};
|
|
36
43
|
const oauthLogin = integration.oauthLogin;
|
|
37
|
-
request[((
|
|
38
|
-
request[((
|
|
39
|
-
request[((
|
|
40
|
-
request[((
|
|
44
|
+
request[((_f = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _f === void 0 ? void 0 : _f.code) || 'code'] = code;
|
|
45
|
+
request[((_g = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _g === void 0 ? void 0 : _g.clientId) || 'client_id'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientId;
|
|
46
|
+
request[((_h = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _h === void 0 ? void 0 : _h.clientSecret) || 'client_secret'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientSecret;
|
|
47
|
+
request[((_j = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _j === void 0 ? void 0 : _j.redirectUri) || 'redirect_uri'] = `${config.baseUrl}${(0, defaults_1.getOauthRoute)(integration)}`;
|
|
41
48
|
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraAccessTokenParameters) {
|
|
42
49
|
Object.entries(oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraAccessTokenParameters).forEach(([key, value]) => (request[key] = value));
|
|
43
50
|
}
|
|
44
|
-
credentials = (yield axios_1.default.post(((
|
|
51
|
+
credentials = (yield axios_1.default.post(((_k = integration.oauthLogin) === null || _k === void 0 ? void 0 : _k.accessTokenUrl) || '', request, {
|
|
45
52
|
headers: { Accept: 'application/json' },
|
|
46
53
|
})).data;
|
|
47
54
|
}
|
|
48
55
|
const oauthCredentials = { originalUrl: req.originalUrl };
|
|
49
|
-
oauthCredentials.accessToken = credentials[((
|
|
56
|
+
oauthCredentials.accessToken = credentials[((_l = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _l === void 0 ? void 0 : _l.accessToken) || 'access_token'];
|
|
50
57
|
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.refresh) {
|
|
51
|
-
oauthCredentials.refreshToken = credentials[((
|
|
58
|
+
oauthCredentials.refreshToken = credentials[((_m = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _m === void 0 ? void 0 : _m.refreshToken) || 'refresh_token'];
|
|
52
59
|
oauthCredentials.expireIn =
|
|
53
|
-
Number(credentials[((
|
|
60
|
+
Number(credentials[((_o = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _o === void 0 ? void 0 : _o.expiresIn) || 'expires_in']) + Date.now() / 1000;
|
|
54
61
|
}
|
|
55
62
|
message.data = oauthCredentials;
|
|
56
|
-
|
|
63
|
+
if (((_p = integration.oauthLogin) === null || _p === void 0 ? void 0 : _p.mode) === 'polling' && state) {
|
|
64
|
+
yield (0, storage_1.getStorage)().saveMetadata(state, oauthCredentials);
|
|
65
|
+
}
|
|
66
|
+
return res.render('oauth', { message: JSON.stringify(message), oauthMode: (_q = integration.oauthLogin) === null || _q === void 0 ? void 0 : _q.mode });
|
|
57
67
|
}
|
|
58
68
|
catch (e) {
|
|
59
69
|
(0, logger_1.logError)(e);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/// <reference types="qs" />
|
|
2
|
+
import { Response } from 'express';
|
|
3
|
+
import { CrowdinClientRequest } from '../../../types';
|
|
4
|
+
import { IntegrationLogic } from '../types';
|
|
5
|
+
export default function handle(integration: IntegrationLogic): (req: CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const storage_1 = require("../../../storage");
|
|
13
|
+
const util_1 = require("../../../util");
|
|
14
|
+
const defaults_1 = require("../util/defaults");
|
|
15
|
+
function handle(integration) {
|
|
16
|
+
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
req.logInfo('Received OAuth polling request');
|
|
18
|
+
const { oauthLogin } = integration;
|
|
19
|
+
if (!oauthLogin) {
|
|
20
|
+
req.logInfo('OAuth login url request is not supported');
|
|
21
|
+
res.status(400).end();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const oauthId = (0, defaults_1.getOAuthPollingId)(req.crowdinContext.clientId);
|
|
25
|
+
const oauthCreds = yield (0, storage_1.getStorage)().getMetadata(oauthId);
|
|
26
|
+
if (oauthCreds) {
|
|
27
|
+
yield (0, storage_1.getStorage)().deleteMetadata(oauthId);
|
|
28
|
+
}
|
|
29
|
+
res.send({ oauthCreds });
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
exports.default = handle;
|
|
@@ -21,9 +21,7 @@ function handle(config, integration) {
|
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
const { loginForm } = req.body;
|
|
24
|
-
const url =
|
|
25
|
-
? oauthLogin.getAuthorizationUrl(`${config.baseUrl}${(0, defaults_1.getOauthRoute)(integration)}`, loginForm)
|
|
26
|
-
: (0, defaults_1.constructOauthUrl)(config, integration);
|
|
24
|
+
const url = (0, defaults_1.constructOauthUrl)({ config, integration, clientId: req.crowdinContext.clientId, loginForm });
|
|
27
25
|
res.send({ url });
|
|
28
26
|
}));
|
|
29
27
|
}
|
|
@@ -49,6 +49,7 @@ const job_info_1 = __importDefault(require("./handlers/job-info"));
|
|
|
49
49
|
const main_1 = __importDefault(require("./handlers/main"));
|
|
50
50
|
const oauth_login_1 = __importDefault(require("./handlers/oauth-login"));
|
|
51
51
|
const oauth_url_1 = __importDefault(require("./handlers/oauth-url"));
|
|
52
|
+
const oauth_polling_1 = __importDefault(require("./handlers/oauth-polling"));
|
|
52
53
|
const settings_save_1 = __importDefault(require("./handlers/settings-save"));
|
|
53
54
|
const subscription_info_1 = __importDefault(require("./handlers/subscription-info"));
|
|
54
55
|
const sync_settings_1 = __importDefault(require("./handlers/sync-settings"));
|
|
@@ -81,6 +82,9 @@ function register({ config, app }) {
|
|
|
81
82
|
if (integrationLogic.oauthLogin) {
|
|
82
83
|
app.get((0, defaults_1.getOauthRoute)(integrationLogic), (0, oauth_login_1.default)(config, integrationLogic));
|
|
83
84
|
app.post('/api/oauth-url', json_response_1.default, (0, crowdin_client_1.default)(config, false, false), (0, oauth_url_1.default)(config, integrationLogic));
|
|
85
|
+
if (integrationLogic.oauthLogin.mode === 'polling') {
|
|
86
|
+
app.post('/api/oauth-polling', json_response_1.default, (0, crowdin_client_1.default)(config, false, false), (0, oauth_polling_1.default)(integrationLogic));
|
|
87
|
+
}
|
|
84
88
|
}
|
|
85
89
|
if (integrationLogic.cronJobs) {
|
|
86
90
|
integrationLogic.cronJobs.forEach((job) => {
|
|
@@ -179,6 +179,7 @@ export interface OAuthLogin {
|
|
|
179
179
|
* Url to refresh token, default will use {@link accessTokenUrl}. Needed when {@link refresh} is enabled
|
|
180
180
|
*/
|
|
181
181
|
refreshTokenUrl?: string;
|
|
182
|
+
mode?: 'standard' | 'polling';
|
|
182
183
|
/**
|
|
183
184
|
* The scopes of access, usually expressed as a list of space-delimited, case-sensitive strings
|
|
184
185
|
*/
|
|
@@ -231,6 +232,10 @@ export interface OAuthLogin {
|
|
|
231
232
|
* default 'expires_in'
|
|
232
233
|
*/
|
|
233
234
|
expiresIn?: string;
|
|
235
|
+
/**
|
|
236
|
+
* default 'state', used for `polling' mode
|
|
237
|
+
*/
|
|
238
|
+
state?: string;
|
|
234
239
|
};
|
|
235
240
|
/**
|
|
236
241
|
* default 'false' which means that the access token has no expiration date
|
|
@@ -4,4 +4,10 @@ import { IntegrationLogic } from '../types';
|
|
|
4
4
|
export declare function getRootFolder(config: Config, integration: IntegrationLogic, client: Crowdin, projectId: number): Promise<SourceFilesModel.Directory | undefined>;
|
|
5
5
|
export declare function getOauthRoute(integration: IntegrationLogic): string;
|
|
6
6
|
export declare function applyIntegrationModuleDefaults(config: Config, integration: IntegrationLogic): void;
|
|
7
|
-
export declare function constructOauthUrl(config
|
|
7
|
+
export declare function constructOauthUrl({ config, integration, clientId, loginForm, }: {
|
|
8
|
+
config: Config;
|
|
9
|
+
integration: IntegrationLogic;
|
|
10
|
+
clientId: string;
|
|
11
|
+
loginForm?: any;
|
|
12
|
+
}): string | undefined;
|
|
13
|
+
export declare function getOAuthPollingId(clientId: string): string;
|
|
@@ -32,7 +32,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.constructOauthUrl = exports.applyIntegrationModuleDefaults = exports.getOauthRoute = exports.getRootFolder = void 0;
|
|
35
|
+
exports.getOAuthPollingId = exports.constructOauthUrl = exports.applyIntegrationModuleDefaults = exports.getOauthRoute = exports.getRootFolder = void 0;
|
|
36
36
|
const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
|
|
37
37
|
function getRootFolder(config, integration, client, projectId) {
|
|
38
38
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -257,18 +257,34 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
exports.applyIntegrationModuleDefaults = applyIntegrationModuleDefaults;
|
|
260
|
-
function constructOauthUrl(config, integration) {
|
|
261
|
-
var _a, _b, _c;
|
|
260
|
+
function constructOauthUrl({ config, integration, clientId, loginForm, }) {
|
|
261
|
+
var _a, _b, _c, _d;
|
|
262
262
|
const oauth = integration.oauthLogin;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
url += `&${((_b = oauth === null || oauth === void 0 ? void 0 : oauth.fieldsMapping) === null || _b === void 0 ? void 0 : _b.redirectUri) || 'redirect_uri'}=${config.baseUrl}${getOauthRoute(integration)}`;
|
|
266
|
-
if (oauth === null || oauth === void 0 ? void 0 : oauth.scope) {
|
|
267
|
-
url += `&${((_c = oauth === null || oauth === void 0 ? void 0 : oauth.fieldsMapping) === null || _c === void 0 ? void 0 : _c.scope) || 'scope'}=${oauth === null || oauth === void 0 ? void 0 : oauth.scope}`;
|
|
263
|
+
if (!oauth) {
|
|
264
|
+
return;
|
|
268
265
|
}
|
|
269
|
-
if (oauth
|
|
270
|
-
|
|
266
|
+
if (oauth.getAuthorizationUrl) {
|
|
267
|
+
return oauth.getAuthorizationUrl(`${config.baseUrl}${getOauthRoute(integration)}`, loginForm);
|
|
268
|
+
}
|
|
269
|
+
if (!oauth.authorizationUrl) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
let url = oauth.authorizationUrl || '';
|
|
273
|
+
url += `?${((_a = oauth.fieldsMapping) === null || _a === void 0 ? void 0 : _a.clientId) || 'client_id'}=${oauth.clientId}`;
|
|
274
|
+
url += `&${((_b = oauth.fieldsMapping) === null || _b === void 0 ? void 0 : _b.redirectUri) || 'redirect_uri'}=${config.baseUrl}${getOauthRoute(integration)}`;
|
|
275
|
+
if (oauth.scope) {
|
|
276
|
+
url += `&${((_c = oauth.fieldsMapping) === null || _c === void 0 ? void 0 : _c.scope) || 'scope'}=${oauth.scope}`;
|
|
277
|
+
}
|
|
278
|
+
if (oauth.mode === 'polling') {
|
|
279
|
+
url += `&${((_d = oauth.fieldsMapping) === null || _d === void 0 ? void 0 : _d.state) || 'state'}=${getOAuthPollingId(clientId)}`;
|
|
280
|
+
}
|
|
281
|
+
if (oauth.extraAutorizationUrlParameters) {
|
|
282
|
+
Object.entries(oauth.extraAutorizationUrlParameters).forEach(([key, value]) => (url += `&${key}=${value}`));
|
|
271
283
|
}
|
|
272
284
|
return url;
|
|
273
285
|
}
|
|
274
286
|
exports.constructOauthUrl = constructOauthUrl;
|
|
287
|
+
function getOAuthPollingId(clientId) {
|
|
288
|
+
return `oauth_${clientId}`;
|
|
289
|
+
}
|
|
290
|
+
exports.getOAuthPollingId = getOAuthPollingId;
|
|
@@ -178,6 +178,7 @@
|
|
|
178
178
|
</body>
|
|
179
179
|
<script type="text/javascript">
|
|
180
180
|
const loginButton = document.querySelector('#login-button');
|
|
181
|
+
let refreshIntervalId;
|
|
181
182
|
|
|
182
183
|
function oauthLogin() {
|
|
183
184
|
{{#if oauthUrl}}
|
|
@@ -209,7 +210,41 @@
|
|
|
209
210
|
}
|
|
210
211
|
|
|
211
212
|
function openOAuthPopup(url) {
|
|
213
|
+
{{#if oauthMode}}
|
|
214
|
+
const oauthMode = '{{{ oauthMode }}}';
|
|
215
|
+
{{else}}
|
|
216
|
+
const oauthMode = undefined;
|
|
217
|
+
{{/if}}
|
|
212
218
|
const oauthWindow = window.open(url, '{{ name }}', 'location=0,status=0,width=800,height=400');
|
|
219
|
+
|
|
220
|
+
if (oauthMode === 'polling') {
|
|
221
|
+
if (refreshIntervalId) {
|
|
222
|
+
clearInterval(refreshIntervalId);
|
|
223
|
+
}
|
|
224
|
+
refreshIntervalId = setInterval(() =>
|
|
225
|
+
checkOrigin()
|
|
226
|
+
.then(queryParams =>
|
|
227
|
+
fetch(`api/oauth-polling${queryParams}`, {
|
|
228
|
+
method: 'POST',
|
|
229
|
+
})
|
|
230
|
+
)
|
|
231
|
+
.then(checkResponse)
|
|
232
|
+
.then(res => {
|
|
233
|
+
if (res.oauthCreds) {
|
|
234
|
+
integrationLogin({
|
|
235
|
+
refreshToken: res.oauthCreds.refreshToken,
|
|
236
|
+
accessToken: res.oauthCreds.accessToken,
|
|
237
|
+
expireIn: res.oauthCreds.expireIn,
|
|
238
|
+
timestamp: res.oauthCreds.timestamp
|
|
239
|
+
});
|
|
240
|
+
if (refreshIntervalId) {
|
|
241
|
+
clearInterval(refreshIntervalId);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}), 2000);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
213
248
|
postPromises['oauth_popup'] = {
|
|
214
249
|
resolve: (data) => {
|
|
215
250
|
if (data.error) {
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
|
-
|
|
2
|
+
{{#if oauthMode}}
|
|
3
|
+
const oauthMode = '{{{ oauthMode }}}';
|
|
4
|
+
{{else}}
|
|
5
|
+
const oauthMode = undefined;
|
|
6
|
+
{{/if}}
|
|
7
|
+
if (oauthMode !== 'polling') {
|
|
8
|
+
window.opener.postMessage('{{{message}}}');
|
|
9
|
+
}
|
|
3
10
|
window.close();
|
|
4
11
|
</script>
|
package/package.json
CHANGED