@aloma.io/integration-sdk 3.7.49 → 3.7.50
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/build/internal/connector/config.d.mts +9 -0
- package/build/internal/connector/config.mjs +50 -0
- package/build/internal/connector/index.d.mts +16 -0
- package/build/internal/connector/index.mjs +39 -0
- package/build/internal/connector/metrics.d.mts +5 -0
- package/build/internal/connector/metrics.mjs +27 -0
- package/build/internal/connector/server/index.d.mts +10 -0
- package/build/internal/connector/server/index.mjs +29 -0
- package/build/internal/connector/server/on-connect/decrypt-config.d.mts +5 -0
- package/build/internal/connector/server/on-connect/decrypt-config.mjs +24 -0
- package/build/internal/connector/server/on-connect/finish-oauth.d.mts +9 -0
- package/build/internal/connector/server/on-connect/finish-oauth.mjs +90 -0
- package/build/internal/connector/server/on-connect/index.d.mts +8 -0
- package/build/internal/connector/server/on-connect/index.mjs +95 -0
- package/build/internal/connector/server/on-connect/make-oauth.d.mts +9 -0
- package/build/internal/connector/server/on-connect/make-oauth.mjs +77 -0
- package/build/internal/connector/server/on-connect/start-oauth.d.mts +4 -0
- package/build/internal/connector/server/on-connect/start-oauth.mjs +27 -0
- package/build/internal/connector/server/on-connect.d.mts +8 -0
- package/build/internal/connector/server/on-connect.mjs +297 -0
- package/build/internal/connector/server/on-message.d.mts +1 -0
- package/build/internal/connector/server/on-message.mjs +14 -0
- package/build/internal/dispatcher/index.d.mts +12 -2
- package/build/internal/dispatcher/index.mjs +4 -3
- package/build/internal/index.d.mts +1 -16
- package/build/internal/index.mjs +1 -423
- package/package.json +1 -1
- package/src/internal/connector/config.mts +57 -0
- package/src/internal/connector/index.mts +48 -0
- package/src/internal/connector/metrics.mts +35 -0
- package/src/internal/connector/server/index.mts +39 -0
- package/src/internal/connector/server/on-connect/decrypt-config.mts +27 -0
- package/src/internal/connector/server/on-connect/finish-oauth.mts +111 -0
- package/src/internal/connector/server/on-connect/index.mts +142 -0
- package/src/internal/connector/server/on-connect/make-oauth.mts +101 -0
- package/src/internal/connector/server/on-connect/start-oauth.mts +35 -0
- package/src/internal/connector/server/on-message.mts +11 -0
- package/src/internal/dispatcher/index.mts +7 -3
- package/src/internal/index.mts +1 -536
@@ -0,0 +1,50 @@
|
|
1
|
+
import JWE from "../util/jwe/index.mjs";
|
2
|
+
import { Config } from "../websocket/config.mjs";
|
3
|
+
export const makeConfig = async ({ id, version, name, introspect, configSchema, icon }) => {
|
4
|
+
const config = new Config({
|
5
|
+
id: id,
|
6
|
+
version: version,
|
7
|
+
name: process.env.HOSTNAME || name,
|
8
|
+
registrationToken: process.env.REGISTRATION_TOKEN,
|
9
|
+
endpoint: process.env.DEVICE_ENDPOINT || "https://connect.aloma.io/",
|
10
|
+
wsEndpoint: process.env.WEBSOCKET_ENDPOINT || "wss://connect.aloma.io/transport/",
|
11
|
+
privateKey: process.env.PRIVATE_KEY,
|
12
|
+
publicKey: process.env.PUBLIC_KEY,
|
13
|
+
introspect,
|
14
|
+
configSchema,
|
15
|
+
icon: icon,
|
16
|
+
});
|
17
|
+
if (Object.keys(configSchema().fields).length) {
|
18
|
+
try {
|
19
|
+
await config.validateKeys();
|
20
|
+
}
|
21
|
+
catch (e) {
|
22
|
+
const haveKey = !!process.env.PRIVATE_KEY;
|
23
|
+
const jwe = new JWE({});
|
24
|
+
var text = "Please double check the env variables";
|
25
|
+
if (!haveKey) {
|
26
|
+
await jwe.newPair();
|
27
|
+
text =
|
28
|
+
"fresh keys generated, set environment variables: \n\nPRIVATE_KEY: " +
|
29
|
+
(await jwe.exportPrivateAsBase64()) +
|
30
|
+
"\n\nPUBLIC_KEY: " +
|
31
|
+
(await jwe.exportPublicAsBase64()) +
|
32
|
+
"\n";
|
33
|
+
}
|
34
|
+
console.log(`
|
35
|
+
Error:
|
36
|
+
|
37
|
+
public (env.PUBLIC_KEY) and private key (env.PRIVATE_KEY) could not be loaded.
|
38
|
+
|
39
|
+
${text}
|
40
|
+
`);
|
41
|
+
await new Promise((resolve) => {
|
42
|
+
setTimeout(() => {
|
43
|
+
resolve(null);
|
44
|
+
}, 2 * 60 * 1000);
|
45
|
+
});
|
46
|
+
throw new Error('could not start');
|
47
|
+
}
|
48
|
+
}
|
49
|
+
return config;
|
50
|
+
};
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { Dispatcher } from "../dispatcher/index.mjs";
|
2
|
+
export declare class Connector {
|
3
|
+
id: any;
|
4
|
+
version: any;
|
5
|
+
name: any;
|
6
|
+
icon: any;
|
7
|
+
dispatcher?: Dispatcher;
|
8
|
+
constructor({ version, id, name, icon }: {
|
9
|
+
version: any;
|
10
|
+
id: any;
|
11
|
+
name: any;
|
12
|
+
icon: any;
|
13
|
+
});
|
14
|
+
configure(): Dispatcher;
|
15
|
+
run(): Promise<void>;
|
16
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Dispatcher } from "../dispatcher/index.mjs";
|
2
|
+
import { makeConfig } from "./config.mjs";
|
3
|
+
import { makeMetrics } from "./metrics.mjs";
|
4
|
+
import { makeServer } from "./server/index.mjs";
|
5
|
+
export class Connector {
|
6
|
+
id;
|
7
|
+
version;
|
8
|
+
name;
|
9
|
+
icon;
|
10
|
+
dispatcher;
|
11
|
+
constructor({ version, id, name, icon }) {
|
12
|
+
this.id = id;
|
13
|
+
this.version = version;
|
14
|
+
this.name = name;
|
15
|
+
this.icon = icon;
|
16
|
+
}
|
17
|
+
configure() {
|
18
|
+
return (this.dispatcher = new Dispatcher());
|
19
|
+
}
|
20
|
+
async run() {
|
21
|
+
console.log(`Running ${this.name} (${this.version})`);
|
22
|
+
const { processPacket, start, introspect, configSchema } = this.dispatcher.build();
|
23
|
+
const config = await makeConfig({
|
24
|
+
id: this.id,
|
25
|
+
version: this.version,
|
26
|
+
name: this.name,
|
27
|
+
introspect,
|
28
|
+
configSchema,
|
29
|
+
icon: this.icon,
|
30
|
+
});
|
31
|
+
await makeMetrics({
|
32
|
+
id: this.id,
|
33
|
+
name: this.name,
|
34
|
+
version: this.version,
|
35
|
+
});
|
36
|
+
const server = await makeServer({ config, configSchema, start, processPacket, dispatcher: this.dispatcher });
|
37
|
+
await server.start();
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import express from "express";
|
2
|
+
import PromClient from "prom-client";
|
3
|
+
export const makeMetrics = async ({ id, name, version }) => {
|
4
|
+
const newMetrics = () => {
|
5
|
+
const metrics = PromClient;
|
6
|
+
const defaultLabels = {
|
7
|
+
service: name,
|
8
|
+
connectorId: id,
|
9
|
+
connectorVersion: version,
|
10
|
+
node: process.env.HOSTNAME || "test",
|
11
|
+
};
|
12
|
+
metrics.register.setDefaultLabels(defaultLabels);
|
13
|
+
metrics.collectDefaultMetrics();
|
14
|
+
return metrics;
|
15
|
+
};
|
16
|
+
const makeMetricsServer = (metrics) => {
|
17
|
+
const app = express();
|
18
|
+
app.get("/metrics", async (request, response, next) => {
|
19
|
+
response.status(200);
|
20
|
+
response.set("Content-type", metrics.contentType);
|
21
|
+
response.send(await metrics.register.metrics());
|
22
|
+
response.end();
|
23
|
+
});
|
24
|
+
return app;
|
25
|
+
};
|
26
|
+
makeMetricsServer(newMetrics()).listen(4050, "0.0.0.0");
|
27
|
+
};
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import Dispatcher from "../../dispatcher/index.mjs";
|
2
|
+
import { Config } from "../../websocket/config.mjs";
|
3
|
+
import { WebsocketConnector } from "../../websocket/index.mjs";
|
4
|
+
export declare const makeServer: ({ config, configSchema, start, processPacket, dispatcher }: {
|
5
|
+
config: Config;
|
6
|
+
configSchema: any;
|
7
|
+
start: any;
|
8
|
+
processPacket: any;
|
9
|
+
dispatcher: Dispatcher;
|
10
|
+
}) => Promise<WebsocketConnector>;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { WebsocketConnector } from "../../websocket/index.mjs";
|
2
|
+
import { onConnect } from "./on-connect/index.mjs";
|
3
|
+
import { onMessage } from "./on-message.mjs";
|
4
|
+
export const makeServer = async ({ config, configSchema, start, processPacket, dispatcher }) => {
|
5
|
+
const server = new WebsocketConnector({
|
6
|
+
config,
|
7
|
+
onConnect: onConnect({ config, configSchema, dispatcher, start }),
|
8
|
+
onMessage: onMessage(processPacket)
|
9
|
+
});
|
10
|
+
const term = async () => {
|
11
|
+
await server.leaving();
|
12
|
+
await new Promise((resolve) => {
|
13
|
+
setTimeout(async () => {
|
14
|
+
await server.close();
|
15
|
+
resolve(null);
|
16
|
+
}, 10000);
|
17
|
+
});
|
18
|
+
process.exit(0);
|
19
|
+
};
|
20
|
+
process.on("uncaughtException", (e) => {
|
21
|
+
console.log(e);
|
22
|
+
});
|
23
|
+
process.on("unhandledRejection", (e) => {
|
24
|
+
console.log(e);
|
25
|
+
});
|
26
|
+
process.on("SIGTERM", term);
|
27
|
+
process.on("SIGINT", term);
|
28
|
+
return server;
|
29
|
+
};
|
@@ -0,0 +1,24 @@
|
|
1
|
+
export const decryptConfig = async ({ configSchema, config, secrets }) => {
|
2
|
+
const decrypted = {};
|
3
|
+
const fields = configSchema().fields;
|
4
|
+
const keys = Object.keys(secrets);
|
5
|
+
const jwe = await config.validateKeys("RSA-OAEP-256");
|
6
|
+
for (var i = 0; i < keys.length; ++i) {
|
7
|
+
const key = keys[i];
|
8
|
+
const value = secrets[key];
|
9
|
+
if (!value)
|
10
|
+
continue;
|
11
|
+
if (fields[key]?.plain || ["endpointUrl"].includes(key)) {
|
12
|
+
decrypted[key] = value;
|
13
|
+
}
|
14
|
+
else {
|
15
|
+
try {
|
16
|
+
decrypted[key] = await jwe.decrypt(value, config.id());
|
17
|
+
}
|
18
|
+
catch (e) {
|
19
|
+
console.log("failed to decrypt key", key, config.id(), e);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
return decrypted;
|
24
|
+
};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import Dispatcher from "../../../dispatcher/index.mjs";
|
2
|
+
import { Config } from "../../../websocket/config.mjs";
|
3
|
+
import { WebsocketConnector } from "../../../websocket/index.mjs";
|
4
|
+
export declare const patchFinishOAuth: ({ dispatcher, decrypted, config, transport }: {
|
5
|
+
dispatcher: Dispatcher;
|
6
|
+
decrypted: any;
|
7
|
+
config: Config;
|
8
|
+
transport: WebsocketConnector;
|
9
|
+
}) => Promise<void>;
|
@@ -0,0 +1,90 @@
|
|
1
|
+
export const patchFinishOAuth = async ({ dispatcher, decrypted, config, transport }) => {
|
2
|
+
dispatcher.finishOAuth = async function (arg) {
|
3
|
+
const tokenURL = process.env.OAUTH_TOKEN_URL ||
|
4
|
+
decrypted.tokenURL ||
|
5
|
+
dispatcher._oauth.tokenURL;
|
6
|
+
if (!dispatcher._oauth)
|
7
|
+
throw new Error("oauth not configured");
|
8
|
+
if (!tokenURL && !dispatcher._oauth.finishOAuth)
|
9
|
+
throw new Error("need tokenURL or finishOAuth(arg)");
|
10
|
+
var data = null;
|
11
|
+
const doFinish = async () => {
|
12
|
+
if (!arg.code || !arg.redirectURI)
|
13
|
+
throw new Error("need code and redirectUri");
|
14
|
+
const clientId = decrypted.clientId ||
|
15
|
+
process.env.OAUTH_CLIENT_ID ||
|
16
|
+
dispatcher._oauth.clientId;
|
17
|
+
if (!clientId)
|
18
|
+
throw new Error("clientId not configured");
|
19
|
+
const clientSecret = decrypted.clientSecret ||
|
20
|
+
process.env.OAUTH_CLIENT_SECRET ||
|
21
|
+
dispatcher._oauth.clientSecret;
|
22
|
+
if (!clientSecret)
|
23
|
+
throw new Error("clientSecret not configured");
|
24
|
+
const additionalTokenArgs = dispatcher._oauth.additionalTokenArgs || {};
|
25
|
+
const useAuthHeader = !!dispatcher._oauth.useAuthHeader;
|
26
|
+
const useCodeChallenge = !!dispatcher._oauth.useCodeChallenge;
|
27
|
+
let body = {
|
28
|
+
grant_type: "authorization_code",
|
29
|
+
...additionalTokenArgs,
|
30
|
+
code: arg.code,
|
31
|
+
redirect_uri: arg.redirectURI,
|
32
|
+
};
|
33
|
+
if (useCodeChallenge) {
|
34
|
+
body.code_verifier = arg.codeVerifier;
|
35
|
+
}
|
36
|
+
let headers = {
|
37
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
38
|
+
Accept: "application/json",
|
39
|
+
};
|
40
|
+
if (useAuthHeader) {
|
41
|
+
headers = {
|
42
|
+
...headers,
|
43
|
+
Authorization: `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
|
44
|
+
};
|
45
|
+
}
|
46
|
+
else {
|
47
|
+
body = {
|
48
|
+
...body,
|
49
|
+
client_id: clientId,
|
50
|
+
client_secret: clientSecret,
|
51
|
+
};
|
52
|
+
}
|
53
|
+
const response = await fetch(tokenURL, {
|
54
|
+
method: "POST",
|
55
|
+
body: new URLSearchParams(body),
|
56
|
+
headers,
|
57
|
+
signal: AbortSignal.timeout(60 * 1000),
|
58
|
+
});
|
59
|
+
const status = await response.status;
|
60
|
+
const text = await response.text();
|
61
|
+
if (status === 200) {
|
62
|
+
const ret = JSON.parse(text);
|
63
|
+
if (ret.error) {
|
64
|
+
throw new Error(`${status} ${ret.error} ${ret.error_description || ""}`);
|
65
|
+
}
|
66
|
+
else if (ret.access_token) {
|
67
|
+
return { ...ret };
|
68
|
+
}
|
69
|
+
else {
|
70
|
+
throw new Error(status + " response has no access_token - " + text);
|
71
|
+
}
|
72
|
+
}
|
73
|
+
else {
|
74
|
+
throw new Error(status + " " + text);
|
75
|
+
}
|
76
|
+
};
|
77
|
+
if (dispatcher._oauth.finishOAuth) {
|
78
|
+
data = await dispatcher._oauth.finishOAuth({
|
79
|
+
arg,
|
80
|
+
doFinish,
|
81
|
+
transport,
|
82
|
+
});
|
83
|
+
}
|
84
|
+
else {
|
85
|
+
data = await doFinish();
|
86
|
+
}
|
87
|
+
const jwe = await config.validateKeys("RSA-OAEP-256");
|
88
|
+
return { value: await jwe.encrypt(data, "none", config.id()) };
|
89
|
+
};
|
90
|
+
};
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import Dispatcher from "../../../dispatcher/index.mjs";
|
2
|
+
import { Config } from "../../../websocket/config.mjs";
|
3
|
+
export declare const onConnect: ({ dispatcher, configSchema, config, start }: {
|
4
|
+
config: Config;
|
5
|
+
configSchema: any;
|
6
|
+
start: any;
|
7
|
+
dispatcher: Dispatcher;
|
8
|
+
}) => (transport: any) => Promise<void>;
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import { init } from "@paralleldrive/cuid2";
|
2
|
+
import Fetcher from "../../../fetcher/fetcher.mjs";
|
3
|
+
import { decryptConfig } from "./decrypt-config.mjs";
|
4
|
+
import { patchFinishOAuth } from "./finish-oauth.mjs";
|
5
|
+
import { makeOAuth } from "./make-oauth.mjs";
|
6
|
+
import { patchStartOAuth } from "./start-oauth.mjs";
|
7
|
+
const cuid = init({ length: 32 });
|
8
|
+
export const onConnect = ({ dispatcher, configSchema, config, start }) => {
|
9
|
+
return async (transport) => {
|
10
|
+
dispatcher.onConfig = async function (secrets) {
|
11
|
+
const decrypted = await decryptConfig({ configSchema, secrets, config });
|
12
|
+
await patchStartOAuth({ dispatcher, decrypted });
|
13
|
+
await patchFinishOAuth({ dispatcher, decrypted, config, transport });
|
14
|
+
const theOAuth = await makeOAuth({ config, transport, decrypted, dispatcher });
|
15
|
+
const getBlob = (id) => {
|
16
|
+
return new Promise((resolve, reject) => {
|
17
|
+
const packet = transport.newPacket({}, (ret) => (ret?.error ? reject(ret.error) : resolve(ret)), `_req-${cuid()}`);
|
18
|
+
packet.method("connector.blob.get");
|
19
|
+
packet.args({
|
20
|
+
id,
|
21
|
+
});
|
22
|
+
transport.send(packet);
|
23
|
+
});
|
24
|
+
};
|
25
|
+
const getBlobContent = (id) => {
|
26
|
+
return new Promise((resolve, reject) => {
|
27
|
+
const packet = transport.newPacket({}, (ret) => ret?.error ? reject(ret.error) : resolve(ret?.content), `_req-${cuid()}`);
|
28
|
+
packet.method("connector.blob.get-content");
|
29
|
+
packet.args({
|
30
|
+
id,
|
31
|
+
});
|
32
|
+
transport.send(packet);
|
33
|
+
});
|
34
|
+
};
|
35
|
+
const createBlob = (args = {}) => {
|
36
|
+
return new Promise((resolve, reject) => {
|
37
|
+
const packet = transport.newPacket({}, (ret) => (ret?.error ? reject(ret.error) : resolve(ret?.id)), `_req-${cuid()}`);
|
38
|
+
packet.method("connector.blob.create");
|
39
|
+
packet.args(args);
|
40
|
+
transport.send(packet);
|
41
|
+
});
|
42
|
+
};
|
43
|
+
let oauthClient;
|
44
|
+
start({
|
45
|
+
config: decrypted,
|
46
|
+
oauth: theOAuth,
|
47
|
+
getBlob,
|
48
|
+
getBlobContent,
|
49
|
+
createBlob,
|
50
|
+
healthCheck: async (controller) => {
|
51
|
+
let result = { ok: true, error: null };
|
52
|
+
try {
|
53
|
+
if (oauthClient) {
|
54
|
+
await oauthClient.__healthCheck();
|
55
|
+
}
|
56
|
+
await controller.__healthCheck();
|
57
|
+
}
|
58
|
+
catch (e) {
|
59
|
+
result.ok = false;
|
60
|
+
result.error = e.message;
|
61
|
+
}
|
62
|
+
const packet = transport.newPacket({});
|
63
|
+
packet.method("connector.health.check");
|
64
|
+
packet.args(result);
|
65
|
+
transport.send(packet);
|
66
|
+
},
|
67
|
+
getClient: (arg) => theOAuth
|
68
|
+
? (oauthClient = theOAuth.getClient(arg))
|
69
|
+
: new Fetcher(arg),
|
70
|
+
newTask: (name, data) => {
|
71
|
+
return new Promise((resolve, reject) => {
|
72
|
+
const packet = transport.newPacket({}, (ret) => (ret?.error ? reject(ret.error) : resolve(ret)), `_req-${cuid()}`);
|
73
|
+
packet.method("connector.task.new");
|
74
|
+
packet.args({
|
75
|
+
name,
|
76
|
+
a: data,
|
77
|
+
});
|
78
|
+
transport.send(packet);
|
79
|
+
});
|
80
|
+
},
|
81
|
+
updateTask: (id, data) => {
|
82
|
+
return new Promise((resolve, reject) => {
|
83
|
+
const packet = transport.newPacket({}, (ret) => (ret?.error ? reject(ret.error) : resolve(ret)), `_req-${cuid()}`);
|
84
|
+
packet.method("connector.task.update");
|
85
|
+
packet.args({
|
86
|
+
id,
|
87
|
+
a: data,
|
88
|
+
});
|
89
|
+
transport.send(packet);
|
90
|
+
});
|
91
|
+
},
|
92
|
+
});
|
93
|
+
};
|
94
|
+
};
|
95
|
+
};
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import Dispatcher from "../../../dispatcher/index.mjs";
|
2
|
+
import { OAuth } from "../../../fetcher/oauth-fetcher.mjs";
|
3
|
+
import { Config } from "../../../websocket/config.mjs";
|
4
|
+
export declare const makeOAuth: ({ config, transport, decrypted, dispatcher }: {
|
5
|
+
config: Config;
|
6
|
+
transport: any;
|
7
|
+
decrypted: any;
|
8
|
+
dispatcher: Dispatcher;
|
9
|
+
}) => Promise<OAuth | null>;
|
@@ -0,0 +1,77 @@
|
|
1
|
+
import { OAuth } from "../../../fetcher/oauth-fetcher.mjs";
|
2
|
+
export const makeOAuth = async ({ config, transport, decrypted, dispatcher }) => {
|
3
|
+
const saveOAuthResult = async (what) => {
|
4
|
+
const jwe = await config.validateKeys("RSA-OAEP-256");
|
5
|
+
const value = await jwe.encrypt(what, "none", config.id());
|
6
|
+
const packet = transport.newPacket({});
|
7
|
+
packet.method("connector.config-update");
|
8
|
+
packet.args({
|
9
|
+
value,
|
10
|
+
});
|
11
|
+
transport.send(packet);
|
12
|
+
};
|
13
|
+
const getRefreshToken = async (refreshToken) => {
|
14
|
+
const tokenURL = process.env.OAUTH_TOKEN_URL ||
|
15
|
+
decrypted.tokenURL ||
|
16
|
+
dispatcher._oauth.tokenURL;
|
17
|
+
const clientId = decrypted.clientId ||
|
18
|
+
process.env.OAUTH_CLIENT_ID ||
|
19
|
+
dispatcher._oauth.clientId;
|
20
|
+
if (!clientId)
|
21
|
+
throw new Error("clientId not configured");
|
22
|
+
const clientSecret = decrypted.clientSecret ||
|
23
|
+
process.env.OAUTH_CLIENT_SECRET ||
|
24
|
+
dispatcher._oauth.clientSecret;
|
25
|
+
if (!clientSecret)
|
26
|
+
throw new Error("clientSecret not configured");
|
27
|
+
const useAuthHeader = !!dispatcher._oauth.useAuthHeader;
|
28
|
+
let headers = {};
|
29
|
+
if (useAuthHeader) {
|
30
|
+
headers = {
|
31
|
+
...headers,
|
32
|
+
Authorization: `Basic ${btoa(`${clientId}:${clientSecret}`)}`,
|
33
|
+
};
|
34
|
+
}
|
35
|
+
const response = await fetch(tokenURL, {
|
36
|
+
method: "POST",
|
37
|
+
body: new URLSearchParams({
|
38
|
+
grant_type: "refresh_token",
|
39
|
+
refresh_token: refreshToken,
|
40
|
+
client_id: clientId,
|
41
|
+
client_secret: clientSecret,
|
42
|
+
}),
|
43
|
+
headers: {
|
44
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
45
|
+
Accept: "application/json",
|
46
|
+
...headers,
|
47
|
+
},
|
48
|
+
signal: AbortSignal.timeout(60 * 1000),
|
49
|
+
});
|
50
|
+
const status = await response.status;
|
51
|
+
const text = await response.text();
|
52
|
+
if (status === 200) {
|
53
|
+
return JSON.parse(text);
|
54
|
+
}
|
55
|
+
else {
|
56
|
+
throw new Error("could not get refresh token " + status + " " + text);
|
57
|
+
}
|
58
|
+
};
|
59
|
+
const theOAuth = dispatcher._oauth
|
60
|
+
? new OAuth(decrypted.oauthResult, saveOAuthResult, getRefreshToken)
|
61
|
+
: null;
|
62
|
+
if (theOAuth) {
|
63
|
+
clearInterval(dispatcher._refreshOAuthToken);
|
64
|
+
if (!(dispatcher._oauth.noPeriodicTokenRefresh === false)) {
|
65
|
+
dispatcher._refreshOAuthToken = setInterval(async () => {
|
66
|
+
try {
|
67
|
+
console.log("refreshing oauth token");
|
68
|
+
await theOAuth.periodicRefresh();
|
69
|
+
}
|
70
|
+
catch (e) {
|
71
|
+
console.log("periodic refresh", e);
|
72
|
+
}
|
73
|
+
}, dispatcher._oauth.tokenRefreshPeriod || 4 * 60 * 60 * 15000);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
return theOAuth;
|
77
|
+
};
|
@@ -0,0 +1,27 @@
|
|
1
|
+
export const patchStartOAuth = async ({ dispatcher, decrypted }) => {
|
2
|
+
dispatcher.startOAuth = async function () {
|
3
|
+
if (!dispatcher._oauth)
|
4
|
+
throw new Error("oauth not configured");
|
5
|
+
const authorizationURL = process.env.OAUTH_AUTHORIZATION_URL ||
|
6
|
+
decrypted.authorizationURL ||
|
7
|
+
dispatcher._oauth.authorizationURL;
|
8
|
+
if (!authorizationURL)
|
9
|
+
throw new Error("authorizationURL not configured");
|
10
|
+
const clientId = decrypted.clientId ||
|
11
|
+
process.env.OAUTH_CLIENT_ID ||
|
12
|
+
dispatcher._oauth.clientId;
|
13
|
+
if (!clientId)
|
14
|
+
throw new Error("clientId not configured");
|
15
|
+
const scopes = process.env.OAUTH_SCOPE ||
|
16
|
+
decrypted.scope ||
|
17
|
+
dispatcher._oauth.scope ||
|
18
|
+
"";
|
19
|
+
const useCodeChallenge = !!dispatcher._oauth.useCodeChallenge;
|
20
|
+
return {
|
21
|
+
url: authorizationURL
|
22
|
+
.replace(/\{\{clientId\}\}/gi, encodeURIComponent(clientId))
|
23
|
+
.replace(/\{\{scope\}\}/gi, encodeURIComponent(scopes)),
|
24
|
+
useCodeChallenge,
|
25
|
+
};
|
26
|
+
};
|
27
|
+
};
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import Dispatcher from "../../dispatcher/index.mjs";
|
2
|
+
import { Config } from "../../websocket/config.mjs";
|
3
|
+
export declare const onConnect: ({ dispatcher, configSchema, config, start }: {
|
4
|
+
config: Config;
|
5
|
+
configSchema: any;
|
6
|
+
start: any;
|
7
|
+
dispatcher: Dispatcher;
|
8
|
+
}) => (transport: any) => void;
|