Skip to content

Commit 789d3a3

Browse files
committed
wip
1 parent cee9a2f commit 789d3a3

File tree

10 files changed

+274
-88
lines changed

10 files changed

+274
-88
lines changed

bin/saddleback.cli.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ const params = program
1313
.option('-i, --input <value>', 'OpenAPI specification, can be a path, url or string content (required)')
1414
.option('-o, --output <value>', 'Output directory (required)')
1515
.option('-c, --config <value>', 'Path to the config file')
16+
.option('-l, --login <value>', 'Login')
17+
.option('-p, --password <value>', 'Password')
18+
.option('-e, --environment <value>', 'Environment')
19+
.option('-uc, --useAutoCore <value>', 'Use fetching Core service swagger.json via login and password')
20+
.option('-ue, --useAutoEvent <value>', 'Use fetching Event service swagger.json via login and password')
21+
.option(
22+
'-un, --useAutoNotification <value>',
23+
'Use fetching Notification service swagger.json via login and password'
24+
)
25+
.option('-uw, --useAutoWorkflows <value>', 'Use fetching Workflows service swagger.json via login and password')
1626
.parse(process.argv)
1727
.opts();
1828

@@ -39,6 +49,13 @@ if (OpenAPI) {
3949
...config,
4050
input: params.input,
4151
output: params.output,
52+
username: params.login,
53+
password: params.password,
54+
useEnvironment: params.environment,
55+
useAutoCoreService: params.useAutoCore,
56+
useAutoEventService: params.useAutoEvent,
57+
useAutoNotificationService: params.useAutoNotification,
58+
useAutoWorkflowsService: params.useAutoWorkflows,
4259
})
4360
.then(() => {
4461
process.exit(0);

src/generateSaddlebackSpec.ts

Lines changed: 70 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,84 +6,93 @@ import { isString } from './utils/isString';
66
import { mapSwaggerRef } from './utils/mapSwaggerRef';
77
import { removeLodashPrefix } from './utils/removeLodashPrefix';
88
import { removeLodashPrefixFromRef } from './utils/removeLodashPrefixFromRef';
9-
import { getApiToken } from './utils/saddleback/getApiToken';
10-
import { getRequestVerificationToken } from './utils/saddleback/getRequestVerificationToken';
11-
import { getSessionCookie } from './utils/saddleback/getSessionCookie';
12-
import { getSwaggerJson } from './utils/saddleback/getSwaggerJson';
9+
import { getSwaggerJsonByEnv } from './utils/saddleback/getSwaggerJsonByEnv';
10+
import { Environment, Service } from './utils/saddleback/getUrlByServiceEnv';
1311
import { Dictionary } from './utils/types';
1412

1513
type Config = Options & {
1614
useSaddlebackServices?: boolean;
1715
additionalModelFileExtension?: boolean;
1816
additionalServiceFileExtension?: boolean;
1917
removeLodashPrefixes?: boolean;
18+
username: string;
19+
password: string;
20+
useAutoCoreService?: boolean;
21+
useAutoEventService?: boolean;
22+
useAutoNotificationService?: boolean;
23+
useAutoWorkflowsService?: boolean;
24+
useEnvironment?: Environment;
2025
};
2126

2227
export const generateSaddlebackSpec = async (config: Config) => {
23-
const username = '[email protected]';
24-
const password = "&cY8at<'S5PfJa#k";
25-
const swaggerUrl = `https://hc-workflowsservice-dev.azurewebsites.net/api-doc/v1/swagger.json`;
28+
const saddlebackGenerator = async (input: string | Record<string, any>, output: string) => {
29+
const openApi: OpenApi = isString(input) ? await getOpenApiSpec(input) : input;
2630

27-
const loginUrl = `https://identity-dev.saddleback.com/account/login`;
28-
const tokenUrl = `https://identity-dev.saddleback.com/connect/authorize/callback`;
31+
if (config.removeLodashPrefixes && openApi.components && openApi.components.schemas) {
32+
const newSchemas: Dictionary<OpenApiSchema> = {};
2933

30-
// params
31-
const client_id = 'cm';
32-
const response_type = 'token';
33-
const scope = 'cm-api.default';
34-
const redirect_uri = (swaggerUrl.match(new RegExp(`.*\.net`)) || [])[0] + '/api-doc-auth-callback';
35-
const response_mode = 'form_post';
36-
const state = 'e57a56201103b8bda3981515294649254a764612d871ecbe7a31efb8e3e66c8b';
37-
const nonce = '78fd83bf2d178a5c5de18f9f7da3269b34f7daa07d4accc28cd0bdb87f9deee8';
38-
const returnUrl = `/connect/authorize/callback?client_id=${client_id}&response_type=${response_type}&scope=${scope}&redirect_uri=${redirect_uri}&state=${state}&nonce=${nonce}&response_mode=${response_mode}`;
39-
40-
const { requestVerificationToken, cookie } = await getRequestVerificationToken({
41-
url: loginUrl,
42-
params: { returnUrl },
43-
});
44-
45-
const { cookie: sessionCookie } = await getSessionCookie({
46-
url: loginUrl,
47-
username,
48-
password,
49-
cookie,
50-
requestVerificationToken,
51-
params: { returnUrl },
52-
});
53-
54-
const { apiToken } = await getApiToken({
55-
url: tokenUrl,
56-
cookie: sessionCookie,
57-
params: {
58-
client_id,
59-
response_type,
60-
scope,
61-
redirect_uri,
62-
state,
63-
nonce,
64-
response_mode,
65-
},
66-
});
67-
68-
const { data: json } = await getSwaggerJson({ url: swaggerUrl, apiToken: apiToken });
69-
70-
const openApi: OpenApi = isString(config.input) ? await getOpenApiSpec(config.input) : config.input;
71-
72-
if (config.removeLodashPrefixes && openApi.components && openApi.components.schemas) {
73-
const newSchemas: Dictionary<OpenApiSchema> = {};
74-
75-
for (const schemaKey in openApi.components.schemas) {
76-
if (openApi.components.schemas.hasOwnProperty(schemaKey)) {
77-
newSchemas[removeLodashPrefix(schemaKey)] = openApi.components.schemas[schemaKey];
34+
for (const schemaKey in openApi.components.schemas) {
35+
if (openApi.components.schemas.hasOwnProperty(schemaKey)) {
36+
newSchemas[removeLodashPrefix(schemaKey)] = openApi.components.schemas[schemaKey];
37+
}
7838
}
39+
40+
openApi.components.schemas = newSchemas;
7941
}
8042

81-
openApi.components.schemas = newSchemas;
82-
}
43+
mapSwaggerRef(openApi, removeLodashPrefixFromRef);
8344

84-
mapSwaggerRef(openApi, removeLodashPrefixFromRef);
45+
await generate({ ...config, input: openApi });
46+
};
8547

86-
await generate({ ...config, input: openApi });
48+
if (!config.useEnvironment) {
49+
await saddlebackGenerator(config.input, config.output);
50+
return;
51+
}
52+
if (config.useAutoCoreService) {
53+
await saddlebackGenerator(
54+
await getSwaggerJsonByEnv({
55+
env: config.useEnvironment,
56+
service: Service.Core,
57+
username: config.username,
58+
password: config.password,
59+
}),
60+
config.output + '/core'
61+
);
62+
}
63+
if (config.useAutoEventService) {
64+
await saddlebackGenerator(
65+
await getSwaggerJsonByEnv({
66+
env: config.useEnvironment,
67+
service: Service.Event,
68+
username: config.username,
69+
password: config.password,
70+
}),
71+
config.output + '/event'
72+
);
73+
}
74+
if (config.useAutoNotificationService) {
75+
await saddlebackGenerator(
76+
await getSwaggerJsonByEnv({
77+
env: config.useEnvironment,
78+
service: Service.Notifications,
79+
username: config.username,
80+
password: config.password,
81+
}),
82+
config.output + '/notifications'
83+
);
84+
}
85+
if (config.useAutoWorkflowsService) {
86+
await saddlebackGenerator(
87+
await getSwaggerJsonByEnv({
88+
env: config.useEnvironment,
89+
service: Service.Workflows,
90+
username: config.username,
91+
password: config.password,
92+
}),
93+
config.output + '/workflows'
94+
);
95+
}
8796
};
8897

8998
export default generateSaddlebackSpec;

src/utils/saddleback/getApiToken.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@ export const getApiToken = async ({
88
url: string;
99
cookie: string;
1010
params: Record<string, string>;
11-
}): Promise<{ apiToken: string }> => {
11+
}): Promise<{ apiToken: string | null }> => {
1212
const response = await axios(url, {
1313
method: 'GET',
1414
headers: {
1515
Cookie: cookie,
1616
},
1717
params,
1818
maxRedirects: 0,
19-
});
19+
}).catch(e => console.log(e));
20+
21+
if (!response) return { apiToken: null };
2022

2123
const regexp = new RegExp(`type='hidden' name='access_token' value='(.*)'`);
2224
const apiToken = response.data.match(regexp)?.[1] || null;

src/utils/saddleback/getRequestVerificationToken.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,22 @@ export const getRequestVerificationToken = async ({
66
}: {
77
url: string;
88
params: Record<string, string>;
9-
}): Promise<{ requestVerificationToken: string; cookie: string }> => {
10-
const response0 = await axios(url, {
9+
}): Promise<{
10+
requestVerificationToken: string | null;
11+
cookie: string | null;
12+
}> => {
13+
const response = await axios(url, {
1114
method: 'GET',
1215
params,
1316
maxRedirects: 0,
14-
});
17+
}).catch(e => console.log(e));
18+
19+
if (!response) return { requestVerificationToken: null, cookie: null };
20+
1521
const regexp = new RegExp(`<input name="__RequestVerificationToken" type="hidden" value="(.*)"`);
16-
const requestVerificationToken = response0.data.match(regexp)?.[1] || null;
22+
const requestVerificationToken = response.data.match(regexp)?.[1] || null;
1723

18-
const cookies = response0.headers['set-cookie'];
24+
const cookies = response?.headers['set-cookie'];
1925
const cookieString = cookies?.reduce((acc, it) => `${acc}${it};`, '') || null;
2026

2127
if (!requestVerificationToken || !cookieString) throw new Error('getRequestVerificationToken failed');

src/utils/saddleback/getStateNonce.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import axios, { AxiosError } from 'axios';
2+
3+
export const getStateNonce = async ({
4+
url,
5+
}: {
6+
url: string;
7+
}): Promise<{ state: string | null; nonce: string | null }> => {
8+
let [state, nonce]: [string | null, string | null] = [null, null];
9+
10+
const response = await axios(`https://${url.match(new RegExp('(.*)/api-doc/'))?.[0]}`, {
11+
method: 'GET',
12+
maxRedirects: 0,
13+
}).catch(e => {
14+
const response = e as AxiosError;
15+
16+
if (response.response && response.response.status === 302) {
17+
const ___location = response.response.headers?.Location || '';
18+
19+
const newRegexp = new RegExp(`state=(.*)&nonce=(.*)[&$]`);
20+
[state, nonce] = ___location.match(newRegexp)?.slice(1) || [null, null];
21+
}
22+
});
23+
24+
return { state, nonce };
25+
};
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import axios, { AxiosResponse } from 'axios';
22

3-
export const getSwaggerJson = async ({ url, apiToken }: { url: string; apiToken: string }): Promise<AxiosResponse> => {
3+
export const getSwaggerJson = async ({
4+
url,
5+
apiToken,
6+
}: {
7+
url: string;
8+
apiToken: string;
9+
}): Promise<AxiosResponse | null> => {
410
const response = await axios(url, {
511
method: 'GET',
612
headers: {
713
Cookie: `apiKey=${apiToken}`,
814
},
915
maxRedirects: 0,
10-
});
11-
return response;
16+
}).catch(e => console.log(e));
17+
18+
return response ?? null;
1219
};
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { getApiToken } from './getApiToken';
2+
import { getRequestVerificationToken } from './getRequestVerificationToken';
3+
import { getSessionCookie } from './getSessionCookie';
4+
import { getStateNonce } from './getStateNonce';
5+
import { getSwaggerJson } from './getSwaggerJson';
6+
import { Environment, getUrlByServiceEnv, Service } from './getUrlByServiceEnv';
7+
8+
export const getSwaggerJsonByEnv = async ({
9+
env,
10+
service,
11+
username,
12+
password,
13+
}: {
14+
env: Environment;
15+
service: Service;
16+
username: string;
17+
password: string;
18+
}): Promise<any> => {
19+
const swaggerUrl = getUrlByServiceEnv({ env, service });
20+
const loginUrl = `https://identity-dev.saddleback.com/account/login`;
21+
const tokenUrl = `https://identity-dev.saddleback.com/connect/authorize/callback`;
22+
23+
// params
24+
const client_id = 'cm';
25+
const response_type = 'token';
26+
const scope = 'cm-api.default';
27+
const redirect_uri = (swaggerUrl.match(new RegExp(`.*\.net`)) || [])[0] + '/api-doc-auth-callback';
28+
const response_mode = 'form_post';
29+
30+
const { state, nonce } = await getStateNonce({ url: swaggerUrl });
31+
32+
if (!state || !nonce) return null;
33+
34+
// const state = 'e57a56201103b8bda3981515294649254a764612d871ecbe7a31efb8e3e66c8b';
35+
// const nonce = '78fd83bf2d178a5c5de18f9f7da3269b34f7daa07d4accc28cd0bdb87f9deee8';
36+
const returnUrl = `/connect/authorize/callback?client_id=${client_id}&response_type=${response_type}&scope=${scope}&redirect_uri=${redirect_uri}&state=${state}&nonce=${nonce}&response_mode=${response_mode}`;
37+
38+
const { requestVerificationToken, cookie } = await getRequestVerificationToken({
39+
url: loginUrl,
40+
params: { returnUrl },
41+
});
42+
43+
if (!requestVerificationToken || !cookie) return null;
44+
45+
const { cookie: sessionCookie } = await getSessionCookie({
46+
url: loginUrl,
47+
username,
48+
password,
49+
cookie,
50+
requestVerificationToken,
51+
params: { returnUrl },
52+
});
53+
54+
const { apiToken } = await getApiToken({
55+
url: tokenUrl,
56+
cookie: sessionCookie,
57+
params: {
58+
client_id,
59+
response_type,
60+
scope,
61+
redirect_uri,
62+
state,
63+
nonce,
64+
response_mode,
65+
},
66+
});
67+
68+
if (!apiToken) return null;
69+
70+
const response = await getSwaggerJson({ url: swaggerUrl, apiToken: apiToken });
71+
72+
if (!response) return null;
73+
74+
return response.data;
75+
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export enum Service {
2+
Workflows = 'workflows',
3+
Event = 'event',
4+
Notifications = 'notifications',
5+
Core = 'core',
6+
}
7+
8+
export enum Environment {
9+
Dev = 'dev',
10+
Stage = 'stage',
11+
Stage2 = 'stage2',
12+
}
13+
14+
export const getUrlByServiceEnv = ({ env, service }: { service: Service; env: Environment }): string => {
15+
switch (service) {
16+
case Service.Core:
17+
return `hc-${env}.saddleback.com/api-doc/all/swagger.json`;
18+
case Service.Notifications:
19+
return `hc-notificationservice-${env}.azurewebsites.net/api-doc/v1/swagger.json`;
20+
case Service.Workflows:
21+
return `https://hc-workflowsservice-${env}.azurewebsites.net/api-doc/v1/swagger.json`;
22+
case Service.Event:
23+
return `hc-eventservice-${env}.azurewebsites.net/api-doc/all/swagger.json`;
24+
}
25+
};

0 commit comments

Comments
 (0)