@soulcode/bexio-oauth 0.1.0 → 0.3.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/README.md +9 -5
- package/dist/claims.d.ts +3 -3
- package/dist/claims.d.ts.map +1 -1
- package/dist/claims.js +5 -5
- package/dist/claims.js.map +1 -1
- package/dist/client.d.ts +4 -137
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +18 -629
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/connect-flow.d.ts +15 -0
- package/dist/connect-flow.d.ts.map +1 -0
- package/dist/connect-flow.js +123 -0
- package/dist/connect-flow.js.map +1 -0
- package/dist/crypto.d.ts +2 -2
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +20 -15
- package/dist/crypto.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/external-tokens.d.ts +8 -0
- package/dist/external-tokens.d.ts.map +1 -0
- package/dist/external-tokens.js +73 -0
- package/dist/external-tokens.js.map +1 -0
- package/dist/flow-cookie.d.ts +23 -0
- package/dist/flow-cookie.d.ts.map +1 -0
- package/dist/flow-cookie.js +44 -0
- package/dist/flow-cookie.js.map +1 -0
- package/dist/grants.d.ts +45 -0
- package/dist/grants.d.ts.map +1 -0
- package/dist/grants.js +143 -0
- package/dist/grants.js.map +1 -0
- package/dist/idle-sweep.d.ts +11 -0
- package/dist/idle-sweep.d.ts.map +1 -0
- package/dist/idle-sweep.js +70 -0
- package/dist/idle-sweep.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/migrations.generated.d.ts +3 -0
- package/dist/migrations.generated.d.ts.map +1 -0
- package/dist/migrations.generated.js +56 -0
- package/dist/migrations.generated.js.map +1 -0
- package/dist/oidc.d.ts +30 -0
- package/dist/oidc.d.ts.map +1 -0
- package/dist/oidc.js +67 -0
- package/dist/oidc.js.map +1 -0
- package/dist/refresh.d.ts +30 -0
- package/dist/refresh.d.ts.map +1 -0
- package/dist/refresh.js +147 -0
- package/dist/refresh.js.map +1 -0
- package/dist/return-to.d.ts +8 -0
- package/dist/return-to.d.ts.map +1 -0
- package/dist/return-to.js +31 -0
- package/dist/return-to.js.map +1 -0
- package/dist/sql.d.ts +6 -1
- package/dist/sql.d.ts.map +1 -1
- package/dist/sql.js +8 -12
- package/dist/sql.js.map +1 -1
- package/dist/store/memory.d.ts.map +1 -1
- package/dist/store/memory.js +82 -46
- package/dist/store/memory.js.map +1 -1
- package/dist/store/postgres.d.ts +4 -4
- package/dist/store/postgres.d.ts.map +1 -1
- package/dist/store/postgres.js +137 -59
- package/dist/store/postgres.js.map +1 -1
- package/dist/store/types.d.ts +61 -21
- package/dist/store/types.d.ts.map +1 -1
- package/dist/types.d.ts +164 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +3 -1
- package/sql/0001_bexio_oauth.sql +48 -0
- package/sql/0001_bexio_grants.sql +0 -32
package/dist/refresh.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import * as oidc from "openid-client";
|
|
3
|
+
import { BexioOAuthError, isBexioOAuthError } from "./errors.js";
|
|
4
|
+
import { bindingOf, decryptFor, issue, resolveGrant } from "./grants.js";
|
|
5
|
+
import { describe } from "./oidc.js";
|
|
6
|
+
import { fetchRole } from "./permissions.js";
|
|
7
|
+
/** Refresh a little before the access token really expires. */
|
|
8
|
+
export const EXPIRY_SKEW_MS = 30_000;
|
|
9
|
+
/** Extra time `getAccessToken` waits for a concurrent refresh beyond the lock TTL. */
|
|
10
|
+
const WAIT_GRACE_MS = 5_000;
|
|
11
|
+
/** Absolute expiries from a token response's `expires_in` / `refresh_expires_in`. */
|
|
12
|
+
export function tokenExpiry(tokens, now) {
|
|
13
|
+
const expiresIn = tokens.expiresIn();
|
|
14
|
+
const refreshExpiresIn = Number(tokens.refresh_expires_in);
|
|
15
|
+
return {
|
|
16
|
+
accessExpiresAt: expiresIn === undefined
|
|
17
|
+
? null
|
|
18
|
+
: new Date(now.getTime() + expiresIn * 1000),
|
|
19
|
+
refreshExpiresAt: Number.isFinite(refreshExpiresIn) && refreshExpiresIn > 0
|
|
20
|
+
? new Date(now.getTime() + refreshExpiresIn * 1000)
|
|
21
|
+
: null,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** True while the access token is valid for longer than the skew. */
|
|
25
|
+
export function isFresh(connection, now) {
|
|
26
|
+
return (connection.accessExpiresAt !== null &&
|
|
27
|
+
connection.accessExpiresAt.getTime() - EXPIRY_SKEW_MS > now.getTime());
|
|
28
|
+
}
|
|
29
|
+
/** A new lock holder's token and lease, starting at `now`. */
|
|
30
|
+
export function lockWindow(ctx, now) {
|
|
31
|
+
return {
|
|
32
|
+
now,
|
|
33
|
+
lockUntil: new Date(now.getTime() + ctx.lockTtlMs),
|
|
34
|
+
lockToken: randomUUID(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Refreshes a connection whose lock the caller holds (`lockToken`). Every
|
|
39
|
+
* write is fenced by the token: if the lock was lost (expired and taken over,
|
|
40
|
+
* or the connection was reconnected meanwhile), the write changes nothing and
|
|
41
|
+
* this returns `null`: the caller re-reads the connection.
|
|
42
|
+
*/
|
|
43
|
+
export async function refreshLocked(ctx, connection, lockToken) {
|
|
44
|
+
const { store, cipher, clock } = ctx;
|
|
45
|
+
if (!connection.refreshToken) {
|
|
46
|
+
if (!(await store.markReauthRequired(connection.id, lockToken, clock())))
|
|
47
|
+
return null;
|
|
48
|
+
throw new BexioOAuthError("reauth_required", "connection has no refresh token; reconnect required");
|
|
49
|
+
}
|
|
50
|
+
let refreshToken;
|
|
51
|
+
try {
|
|
52
|
+
refreshToken = await decryptFor(cipher, connection, connection.refreshToken);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// Usually a keyring mistake (a key removed too early): don't burn the
|
|
56
|
+
// connection, so restoring the key fixes it.
|
|
57
|
+
await store.releaseRefreshLock(connection.id, lockToken);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
let tokens;
|
|
61
|
+
try {
|
|
62
|
+
tokens = await oidc.refreshTokenGrant(await ctx.oidc.config(), refreshToken);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof oidc.ResponseBodyError &&
|
|
66
|
+
error.error === "invalid_grant") {
|
|
67
|
+
// A reconnect during the refresh restarts the chain at Bexio, which
|
|
68
|
+
// rejects this (older) refresh token. If the reconnect's write already
|
|
69
|
+
// landed, it cleared our lock: nothing is marked and the caller reads
|
|
70
|
+
// the new tokens. If it lands later, it revives the connection then.
|
|
71
|
+
if (!(await store.markReauthRequired(connection.id, lockToken, clock())))
|
|
72
|
+
return null;
|
|
73
|
+
throw new BexioOAuthError("reauth_required", "Bexio rejected the refresh token; reconnect required", { cause: describe(error) });
|
|
74
|
+
}
|
|
75
|
+
await store.releaseRefreshLock(connection.id, lockToken);
|
|
76
|
+
if (isBexioOAuthError(error))
|
|
77
|
+
throw error;
|
|
78
|
+
throw new BexioOAuthError("idp_error", "token refresh failed", {
|
|
79
|
+
cause: describe(error),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const now = clock();
|
|
83
|
+
const binding = bindingOf(connection);
|
|
84
|
+
// null: lock lost while refreshing (someone reconnected, or our lock
|
|
85
|
+
// expired and another caller took over). Their write wins.
|
|
86
|
+
return store.saveRefreshed(connection.id, lockToken, {
|
|
87
|
+
accessToken: await cipher.encrypt(tokens.access_token, binding),
|
|
88
|
+
refreshToken: tokens.refresh_token
|
|
89
|
+
? await cipher.encrypt(tokens.refresh_token, binding)
|
|
90
|
+
: null,
|
|
91
|
+
...tokenExpiry(tokens, now),
|
|
92
|
+
scope: tokens.scope ?? null,
|
|
93
|
+
role: await fetchRole(ctx.fetchImpl, ctx.apiBaseUrl, tokens.access_token),
|
|
94
|
+
now,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
98
|
+
/** `BexioOAuth.getAccessToken`. */
|
|
99
|
+
export async function getAccessToken(ctx, selector) {
|
|
100
|
+
const { store, clock } = ctx;
|
|
101
|
+
const grant = await resolveGrant(store, selector);
|
|
102
|
+
let connection = grant.connection;
|
|
103
|
+
const deadline = clock().getTime() + ctx.lockTtlMs + WAIT_GRACE_MS;
|
|
104
|
+
let wait = 50;
|
|
105
|
+
const reread = async () => {
|
|
106
|
+
const current = await store.getConnection(connection.id);
|
|
107
|
+
if (!current)
|
|
108
|
+
throw new BexioOAuthError("not_connected", "grant was disconnected");
|
|
109
|
+
return current;
|
|
110
|
+
};
|
|
111
|
+
for (;;) {
|
|
112
|
+
if (connection.status === "reauth_required") {
|
|
113
|
+
throw new BexioOAuthError("reauth_required", "grant needs to be reconnected");
|
|
114
|
+
}
|
|
115
|
+
const now = clock();
|
|
116
|
+
if (isFresh(connection, now))
|
|
117
|
+
return issue(ctx.cipher, grant, connection);
|
|
118
|
+
// Every iteration that would do more work is bounded, whether the last
|
|
119
|
+
// one waited for another refresher or lost its own lock.
|
|
120
|
+
if (now.getTime() > deadline) {
|
|
121
|
+
throw new BexioOAuthError("idp_error", "timed out waiting for a concurrent token refresh");
|
|
122
|
+
}
|
|
123
|
+
// Discovery outside the lock, so a cold start doesn't eat into it.
|
|
124
|
+
await ctx.oidc.config();
|
|
125
|
+
const window = lockWindow(ctx, clock());
|
|
126
|
+
const locked = await store.acquireRefreshLock({
|
|
127
|
+
id: connection.id,
|
|
128
|
+
...window,
|
|
129
|
+
accessExpiresBefore: new Date(now.getTime() + EXPIRY_SKEW_MS),
|
|
130
|
+
});
|
|
131
|
+
if (locked) {
|
|
132
|
+
const refreshed = await refreshLocked(ctx, locked, window.lockToken);
|
|
133
|
+
if (refreshed)
|
|
134
|
+
return issue(ctx.cipher, grant, refreshed);
|
|
135
|
+
// Lost the lock to a reconnect or another refresher: look at their
|
|
136
|
+
// result before anything else (it may be fresh, or reauth_required).
|
|
137
|
+
connection = await reread();
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
// Someone else (possibly for another owner of this connection) is
|
|
141
|
+
// refreshing, or just did: wait for their result.
|
|
142
|
+
await sleep(wait);
|
|
143
|
+
wait = Math.min(wait * 2, 1_000);
|
|
144
|
+
connection = await reread();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=refresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.js","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Only same-origin relative paths: blocks open redirects via `returnTo`.
|
|
3
|
+
* Parsed with the URL parser (the same one the redirect will go through), so
|
|
4
|
+
* tricks like `/\t/evil.example` are caught, and normalized to path+query+hash.
|
|
5
|
+
* Returns `fallback` for an empty value; throws `invalid_config` otherwise.
|
|
6
|
+
*/
|
|
7
|
+
export declare function safeReturnTo(value: string | undefined, fallback: string): string;
|
|
8
|
+
//# sourceMappingURL=return-to.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"return-to.d.ts","sourceRoot":"","sources":["../src/return-to.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,MAAM,GACf,MAAM,CAqBR"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BexioOAuthError } from "./errors.js";
|
|
2
|
+
const RETURN_TO_BASE = "https://return-to.invalid";
|
|
3
|
+
/**
|
|
4
|
+
* Only same-origin relative paths: blocks open redirects via `returnTo`.
|
|
5
|
+
* Parsed with the URL parser (the same one the redirect will go through), so
|
|
6
|
+
* tricks like `/\t/evil.example` are caught, and normalized to path+query+hash.
|
|
7
|
+
* Returns `fallback` for an empty value; throws `invalid_config` otherwise.
|
|
8
|
+
*/
|
|
9
|
+
export function safeReturnTo(value, fallback) {
|
|
10
|
+
if (!value)
|
|
11
|
+
return fallback;
|
|
12
|
+
const invalid = () => new BexioOAuthError("invalid_config", "returnTo must be a relative path like /settings");
|
|
13
|
+
// eslint-disable-next-line no-control-regex
|
|
14
|
+
if (!value.startsWith("/") || /[\u0000-\u001f\\]/.test(value))
|
|
15
|
+
throw invalid();
|
|
16
|
+
let url;
|
|
17
|
+
try {
|
|
18
|
+
url = new URL(value, RETURN_TO_BASE);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
throw invalid();
|
|
22
|
+
}
|
|
23
|
+
if (url.origin !== RETURN_TO_BASE)
|
|
24
|
+
throw invalid();
|
|
25
|
+
// Dot segments can collapse to "//host" (e.g. "/.//evil.example"), which a
|
|
26
|
+
// browser reads as protocol-relative: check the normalized result too.
|
|
27
|
+
if (url.pathname.startsWith("//"))
|
|
28
|
+
throw invalid();
|
|
29
|
+
return `${url.pathname}${url.search}${url.hash}`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=return-to.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"return-to.js","sourceRoot":"","sources":["../src/return-to.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,cAAc,GAAG,2BAA2B,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,KAAyB,EACzB,QAAgB;IAEhB,IAAI,CAAC,KAAK;QAAE,OAAO,QAAQ,CAAC;IAC5B,MAAM,OAAO,GAAG,GAAG,EAAE,CACnB,IAAI,eAAe,CACjB,gBAAgB,EAChB,iDAAiD,CAClD,CAAC;IACJ,4CAA4C;IAC5C,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC;QAC3D,MAAM,OAAO,EAAE,CAAC;IAClB,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,OAAO,EAAE,CAAC;IAClB,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,cAAc;QAAE,MAAM,OAAO,EAAE,CAAC;IACnD,2EAA2E;IAC3E,uEAAuE;IACvE,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,MAAM,OAAO,EAAE,CAAC;IACnD,OAAO,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;AACnD,CAAC"}
|
package/dist/sql.d.ts
CHANGED
|
@@ -4,6 +4,11 @@ export interface Migration {
|
|
|
4
4
|
name: string;
|
|
5
5
|
sql: string;
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* The schema migrations shipped with this version, in order.
|
|
9
|
+
*
|
|
10
|
+
* The SQL is embedded in the build (generated from `sql/*.sql`), not read from
|
|
11
|
+
* disk, so this works unchanged when a bundler inlines the library.
|
|
12
|
+
*/
|
|
8
13
|
export declare function migrations(): Promise<Migration[]>;
|
|
9
14
|
//# sourceMappingURL=sql.d.ts.map
|
package/dist/sql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,SAAS;IACxB,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAEvD"}
|
package/dist/sql.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { MIGRATIONS } from "./migrations.generated.js";
|
|
2
|
+
/**
|
|
3
|
+
* The schema migrations shipped with this version, in order.
|
|
4
|
+
*
|
|
5
|
+
* The SQL is embedded in the build (generated from `sql/*.sql`), not read from
|
|
6
|
+
* disk, so this works unchanged when a bundler inlines the library.
|
|
7
|
+
*/
|
|
5
8
|
export async function migrations() {
|
|
6
|
-
|
|
7
|
-
.filter((f) => /^\d{4}_.+\.sql$/.test(f))
|
|
8
|
-
.sort();
|
|
9
|
-
return Promise.all(files.map(async (name) => ({
|
|
10
|
-
number: Number.parseInt(name.slice(0, 4), 10),
|
|
11
|
-
name,
|
|
12
|
-
sql: await readFile(new URL(name, SQL_DIR), "utf8"),
|
|
13
|
-
})));
|
|
9
|
+
return MIGRATIONS.map((m) => ({ ...m }));
|
|
14
10
|
}
|
|
15
11
|
//# sourceMappingURL=sql.js.map
|
package/dist/sql.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.js","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"sql.js","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AASvD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/store/memory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/store/memory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAIV,UAAU,EAGX,MAAM,YAAY,CAAC;AASpB;;;GAGG;AACH,wBAAgB,WAAW,IAAI,UAAU,CA0JxC"}
|
package/dist/store/memory.js
CHANGED
|
@@ -4,42 +4,86 @@ import { randomUUID } from "node:crypto";
|
|
|
4
4
|
* lives in this process only.
|
|
5
5
|
*/
|
|
6
6
|
export function memoryStore() {
|
|
7
|
-
const
|
|
7
|
+
const connections = new Map();
|
|
8
|
+
const grants = new Map();
|
|
8
9
|
const lockTokens = new Map();
|
|
9
10
|
const copy = (row) => ({ ...row });
|
|
11
|
+
const joined = (grant) => ({
|
|
12
|
+
id: grant.id,
|
|
13
|
+
ownerId: grant.ownerId,
|
|
14
|
+
createdAt: grant.createdAt,
|
|
15
|
+
connection: copy(connections.get(grant.connectionId)),
|
|
16
|
+
});
|
|
17
|
+
const held = (id, lockToken) => {
|
|
18
|
+
const row = connections.get(id);
|
|
19
|
+
if (!row || lockTokens.get(id) !== lockToken)
|
|
20
|
+
return null;
|
|
21
|
+
lockTokens.delete(id);
|
|
22
|
+
row.refreshLockedUntil = null;
|
|
23
|
+
return row;
|
|
24
|
+
};
|
|
10
25
|
return {
|
|
11
26
|
async upsertGrant(input) {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
const { ownerId, now, ...fields } = input;
|
|
28
|
+
const existing = [...connections.values()].find((c) => c.companyId === input.companyId && c.userId === input.userId);
|
|
29
|
+
// An older authorization than the stored one only links the grant
|
|
30
|
+
// (see GrantUpsert).
|
|
31
|
+
const connection = existing && input.authorizedAt < existing.authorizedAt
|
|
32
|
+
? existing
|
|
33
|
+
: {
|
|
34
|
+
id: existing?.id ?? randomUUID(),
|
|
35
|
+
...fields,
|
|
36
|
+
status: "active",
|
|
37
|
+
refreshLockedUntil: null,
|
|
38
|
+
lastRefreshedAt: now,
|
|
39
|
+
createdAt: existing?.createdAt ?? now,
|
|
40
|
+
updatedAt: now,
|
|
41
|
+
};
|
|
42
|
+
if (connection !== existing) {
|
|
43
|
+
connections.set(connection.id, connection);
|
|
44
|
+
lockTokens.delete(connection.id);
|
|
45
|
+
}
|
|
46
|
+
let grant = [...grants.values()].find((g) => g.ownerId === ownerId && g.connectionId === connection.id);
|
|
47
|
+
if (!grant) {
|
|
48
|
+
grant = {
|
|
49
|
+
id: randomUUID(),
|
|
50
|
+
ownerId,
|
|
51
|
+
connectionId: connection.id,
|
|
52
|
+
createdAt: now,
|
|
53
|
+
};
|
|
54
|
+
grants.set(grant.id, grant);
|
|
55
|
+
}
|
|
56
|
+
return joined(grant);
|
|
28
57
|
},
|
|
29
58
|
async findGrants({ ownerId, companyId, grantId }) {
|
|
30
|
-
return [...
|
|
31
|
-
.filter((
|
|
32
|
-
(companyId === undefined ||
|
|
33
|
-
|
|
59
|
+
return [...grants.values()]
|
|
60
|
+
.filter((g) => g.ownerId === ownerId &&
|
|
61
|
+
(companyId === undefined ||
|
|
62
|
+
connections.get(g.connectionId).companyId === companyId) &&
|
|
63
|
+
(grantId === undefined || g.id === grantId))
|
|
34
64
|
.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime())
|
|
35
|
-
.map(
|
|
65
|
+
.map(joined);
|
|
36
66
|
},
|
|
37
|
-
async
|
|
38
|
-
|
|
67
|
+
async deleteGrant(id) {
|
|
68
|
+
grants.delete(id);
|
|
69
|
+
},
|
|
70
|
+
async getConnection(id) {
|
|
71
|
+
const row = connections.get(id);
|
|
39
72
|
return row ? copy(row) : null;
|
|
40
73
|
},
|
|
74
|
+
async deleteUnusedConnection(id) {
|
|
75
|
+
const row = connections.get(id);
|
|
76
|
+
if (!row || [...grants.values()].some((g) => g.connectionId === id))
|
|
77
|
+
return null;
|
|
78
|
+
connections.delete(id);
|
|
79
|
+
lockTokens.delete(id);
|
|
80
|
+
return {
|
|
81
|
+
connection: copy(row),
|
|
82
|
+
userHasOtherConnections: [...connections.values()].some((c) => c.userId === row.userId),
|
|
83
|
+
};
|
|
84
|
+
},
|
|
41
85
|
async acquireRefreshLock(req) {
|
|
42
|
-
const row =
|
|
86
|
+
const row = connections.get(req.id);
|
|
43
87
|
if (!row || row.status !== "active")
|
|
44
88
|
return null;
|
|
45
89
|
if (row.refreshLockedUntil && row.refreshLockedUntil > req.now)
|
|
@@ -56,10 +100,9 @@ export function memoryStore() {
|
|
|
56
100
|
return copy(row);
|
|
57
101
|
},
|
|
58
102
|
async saveRefreshed(id, lockToken, refresh) {
|
|
59
|
-
const row =
|
|
60
|
-
if (!row
|
|
103
|
+
const row = held(id, lockToken);
|
|
104
|
+
if (!row)
|
|
61
105
|
return null;
|
|
62
|
-
lockTokens.delete(id);
|
|
63
106
|
row.accessToken = refresh.accessToken;
|
|
64
107
|
row.refreshToken = refresh.refreshToken ?? row.refreshToken;
|
|
65
108
|
row.accessExpiresAt = refresh.accessExpiresAt;
|
|
@@ -67,34 +110,27 @@ export function memoryStore() {
|
|
|
67
110
|
row.scope = refresh.scope ?? row.scope;
|
|
68
111
|
row.role = refresh.role ?? row.role;
|
|
69
112
|
row.status = "active";
|
|
70
|
-
row.refreshLockedUntil = null;
|
|
71
113
|
row.lastRefreshedAt = refresh.now;
|
|
72
114
|
row.updatedAt = refresh.now;
|
|
73
115
|
return copy(row);
|
|
74
116
|
},
|
|
75
117
|
async markReauthRequired(id, lockToken, now) {
|
|
76
|
-
const row =
|
|
77
|
-
if (!row
|
|
78
|
-
return;
|
|
79
|
-
lockTokens.delete(id);
|
|
118
|
+
const row = held(id, lockToken);
|
|
119
|
+
if (!row)
|
|
120
|
+
return null;
|
|
80
121
|
row.status = "reauth_required";
|
|
81
|
-
row.refreshLockedUntil = null;
|
|
82
122
|
row.updatedAt = now;
|
|
123
|
+
return copy(row);
|
|
83
124
|
},
|
|
84
125
|
async releaseRefreshLock(id, lockToken) {
|
|
85
|
-
|
|
86
|
-
if (!row || lockTokens.get(id) !== lockToken)
|
|
87
|
-
return;
|
|
88
|
-
lockTokens.delete(id);
|
|
89
|
-
row.refreshLockedUntil = null;
|
|
90
|
-
},
|
|
91
|
-
async deleteGrant(id) {
|
|
92
|
-
rows.delete(id);
|
|
93
|
-
lockTokens.delete(id);
|
|
126
|
+
held(id, lockToken);
|
|
94
127
|
},
|
|
95
|
-
async
|
|
96
|
-
|
|
97
|
-
|
|
128
|
+
async listIdleConnections({ refreshedBefore, limit }) {
|
|
129
|
+
const linked = new Set([...grants.values()].map((g) => g.connectionId));
|
|
130
|
+
return [...connections.values()]
|
|
131
|
+
.filter((c) => c.status === "active" &&
|
|
132
|
+
c.lastRefreshedAt < refreshedBefore &&
|
|
133
|
+
linked.has(c.id))
|
|
98
134
|
.sort((a, b) => a.lastRefreshedAt.getTime() - b.lastRefreshedAt.getTime())
|
|
99
135
|
.slice(0, limit)
|
|
100
136
|
.map(copy);
|
package/dist/store/memory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/store/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../src/store/memory.ts"],"names":[],"mappings":"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"}
|
package/dist/store/postgres.d.ts
CHANGED
|
@@ -5,13 +5,13 @@ import type { GrantStore } from "./types.js";
|
|
|
5
5
|
*/
|
|
6
6
|
export interface SqlClient {
|
|
7
7
|
query(text: string, params?: unknown[]): Promise<{
|
|
8
|
-
rows:
|
|
8
|
+
rows: unknown[];
|
|
9
9
|
}>;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
* `npx @soulcode/bexio-oauth sql`). Every operation is a single
|
|
14
|
-
* so it works through transaction-mode poolers and HTTP drivers.
|
|
12
|
+
* Store on the `bexio_connections` and `bexio_grants` tables (create them
|
|
13
|
+
* with `npx @soulcode/bexio-oauth sql`). Every operation is a single
|
|
14
|
+
* statement, so it works through transaction-mode poolers and HTTP drivers.
|
|
15
15
|
*/
|
|
16
16
|
export declare function postgresStore(sql: SqlClient): GrantStore;
|
|
17
17
|
//# sourceMappingURL=postgres.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/store/postgres.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../src/store/postgres.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiC,UAAU,EAAE,MAAM,YAAY,CAAC;AAE5E;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CACvE;AA4HD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,SAAS,GAAG,UAAU,CA0MxD"}
|