@block-auth.io/node 0.0.0-stage → 0.1.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 +32 -2
- package/dist/express.cjs +71 -0
- package/dist/express.cjs.map +1 -0
- package/dist/express.d.cts +8 -0
- package/dist/express.d.ts +8 -0
- package/dist/express.js +63 -0
- package/dist/express.js.map +1 -0
- package/dist/index.cjs +391 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +383 -0
- package/dist/index.js.map +1 -0
- package/dist/routes-DR0gMSlM.d.cts +132 -0
- package/dist/routes-DR0gMSlM.d.ts +132 -0
- package/package.json +53 -4
package/README.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @block-auth.io/node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Block-Auth backend SDK for Node.js 18+. It redeems the login code of the Block-Auth widget, keeps the
|
|
4
|
+
session in your server and verifies the Block-Auth webhooks.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npm install @block-auth.io/node express express-session
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import express from 'express'
|
|
12
|
+
import session from 'express-session'
|
|
13
|
+
import { BlockAuthRoutes } from '@block-auth.io/node'
|
|
14
|
+
import { blockauthRouter } from '@block-auth.io/node/express'
|
|
15
|
+
|
|
16
|
+
const routes = new BlockAuthRoutes({
|
|
17
|
+
apiKey: process.env.BLOCKAUTH_API_KEY,
|
|
18
|
+
apiSecret: process.env.BLOCKAUTH_API_SECRET,
|
|
19
|
+
appUrl: process.env.APP_URL,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const app = express()
|
|
23
|
+
app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, cookie: { httpOnly: true, sameSite: 'lax', secure: true } }))
|
|
24
|
+
app.use(blockauthRouter(routes))
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This serves `POST /code`, `GET /me`, `POST /logout`, `GET|POST /link` and `POST /webhook` under
|
|
28
|
+
`/auth/blockauth`, the default `authEndpoint` of the Block-Auth widget. Mount `blockauthRouter` before
|
|
29
|
+
`express.json()` so the webhook signature is checked against the raw body.
|
|
30
|
+
|
|
31
|
+
All the options (allowed origins, session duration, base path, enabled routes and the `onLogin`,
|
|
32
|
+
`onLogout`, `appUser`, `onLinked`, `onSignout`, `onUnlinked`, `isReplay` and `isRevoked` hooks) and
|
|
33
|
+
the manual integration with `AuthCodeClient` are in the [documentation](https://docs.block-auth.io/).
|
package/dist/express.cjs
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var express = require('express');
|
|
4
|
+
|
|
5
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
|
+
|
|
7
|
+
var express__default = /*#__PURE__*/_interopDefault(express);
|
|
8
|
+
|
|
9
|
+
// src/express.ts
|
|
10
|
+
var MAX_BODY = "64kb";
|
|
11
|
+
function sessionOf(req) {
|
|
12
|
+
const session = req.session;
|
|
13
|
+
if (!session || typeof session.regenerate !== "function") {
|
|
14
|
+
throw new Error("Block-Auth routes need express-session (or a compatible req.session) before blockauthRouter");
|
|
15
|
+
}
|
|
16
|
+
return session;
|
|
17
|
+
}
|
|
18
|
+
function expressSessionStore(req) {
|
|
19
|
+
return {
|
|
20
|
+
get: (key) => sessionOf(req)[key],
|
|
21
|
+
set: (key, value) => {
|
|
22
|
+
sessionOf(req)[key] = value;
|
|
23
|
+
},
|
|
24
|
+
remove: (key) => {
|
|
25
|
+
delete sessionOf(req)[key];
|
|
26
|
+
},
|
|
27
|
+
regenerate: () => new Promise((resolve, reject) => {
|
|
28
|
+
const { cookie: _cookie, regenerate: _regenerate, ...kept } = sessionOf(req);
|
|
29
|
+
sessionOf(req).regenerate((err) => {
|
|
30
|
+
if (err) return reject(err);
|
|
31
|
+
Object.assign(sessionOf(req), kept);
|
|
32
|
+
resolve();
|
|
33
|
+
});
|
|
34
|
+
})
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function rawBodyOf(req, isWebhook) {
|
|
38
|
+
if (Buffer.isBuffer(req.body)) return req.body;
|
|
39
|
+
if (req.body && typeof req.body === "object" && Object.keys(req.body).length > 0) {
|
|
40
|
+
if (isWebhook) {
|
|
41
|
+
throw new Error("Mount blockauthRouter before express.json(): the webhook signature needs the raw body");
|
|
42
|
+
}
|
|
43
|
+
return Buffer.from(JSON.stringify(req.body), "utf8");
|
|
44
|
+
}
|
|
45
|
+
return Buffer.alloc(0);
|
|
46
|
+
}
|
|
47
|
+
function sendRouteResponse(res, result) {
|
|
48
|
+
res.status(result.status).set("Cache-Control", "no-store").json(result.body);
|
|
49
|
+
}
|
|
50
|
+
function blockauthRouter(routes, session = expressSessionStore) {
|
|
51
|
+
const router = express__default.default.Router();
|
|
52
|
+
router.use(routes.basePath, express__default.default.raw({ type: () => true, limit: MAX_BODY }), async (req, res, next) => {
|
|
53
|
+
try {
|
|
54
|
+
const path = routes.basePath + req.path;
|
|
55
|
+
const rawBody = rawBodyOf(req, path === `${routes.basePath}/webhook`);
|
|
56
|
+
const context = { session: session(req), request: req };
|
|
57
|
+
const result = await routes.dispatch(req.method, path, rawBody, (name) => req.get(name), context);
|
|
58
|
+
if (!result) return next();
|
|
59
|
+
sendRouteResponse(res, result);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
next(err);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return router;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
exports.blockauthRouter = blockauthRouter;
|
|
68
|
+
exports.expressSessionStore = expressSessionStore;
|
|
69
|
+
exports.sendRouteResponse = sendRouteResponse;
|
|
70
|
+
//# sourceMappingURL=express.cjs.map
|
|
71
|
+
//# sourceMappingURL=express.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/express.ts"],"names":["express"],"mappings":"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","file":"express.cjs","sourcesContent":["import express, { type Request, type Response, type Router } from 'express';\n\nimport { type BlockAuthRoutes, type RouteContext, type RouteResponse, type SessionStore } from './routes';\n\nconst MAX_BODY = '64kb';\n\ntype SessionData = Record<string, unknown> & {\n regenerate(callback: (err?: unknown) => void): void;\n cookie?: unknown;\n};\n\nfunction sessionOf(req: Request): SessionData {\n const session = (req as Request & { session?: SessionData }).session;\n if (!session || typeof session.regenerate !== 'function') {\n throw new Error('Block-Auth routes need express-session (or a compatible req.session) before blockauthRouter');\n }\n return session;\n}\n\nexport function expressSessionStore(req: Request): SessionStore {\n return {\n get: (key) => sessionOf(req)[key],\n set: (key, value) => {\n sessionOf(req)[key] = value;\n },\n remove: (key) => {\n delete sessionOf(req)[key];\n },\n regenerate: () =>\n new Promise<void>((resolve, reject) => {\n const { cookie: _cookie, regenerate: _regenerate, ...kept } = sessionOf(req);\n sessionOf(req).regenerate((err) => {\n if (err) return reject(err);\n Object.assign(sessionOf(req), kept);\n resolve();\n });\n }),\n };\n}\n\nfunction rawBodyOf(req: Request, isWebhook: boolean): Buffer {\n if (Buffer.isBuffer(req.body)) return req.body;\n if (req.body && typeof req.body === 'object' && Object.keys(req.body).length > 0) {\n if (isWebhook) {\n throw new Error('Mount blockauthRouter before express.json(): the webhook signature needs the raw body');\n }\n return Buffer.from(JSON.stringify(req.body), 'utf8');\n }\n return Buffer.alloc(0);\n}\n\nexport function sendRouteResponse(res: Response, result: RouteResponse): void {\n res.status(result.status).set('Cache-Control', 'no-store').json(result.body);\n}\n\nexport function blockauthRouter(\n routes: BlockAuthRoutes,\n session: (req: Request) => SessionStore = expressSessionStore,\n): Router {\n const router = express.Router();\n router.use(routes.basePath, express.raw({ type: () => true, limit: MAX_BODY }), async (req, res, next) => {\n try {\n const path = routes.basePath + req.path;\n const rawBody = rawBodyOf(req, path === `${routes.basePath}/webhook`);\n const context: RouteContext = { session: session(req), request: req };\n const result = await routes.dispatch(req.method, path, rawBody, (name) => req.get(name), context);\n if (!result) return next();\n sendRouteResponse(res, result);\n } catch (err) {\n next(err);\n }\n });\n return router;\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Request, Router, Response } from 'express';
|
|
2
|
+
import { B as BlockAuthRoutes, S as SessionStore, R as RouteResponse } from './routes-DR0gMSlM.cjs';
|
|
3
|
+
|
|
4
|
+
declare function expressSessionStore(req: Request): SessionStore;
|
|
5
|
+
declare function sendRouteResponse(res: Response, result: RouteResponse): void;
|
|
6
|
+
declare function blockauthRouter(routes: BlockAuthRoutes, session?: (req: Request) => SessionStore): Router;
|
|
7
|
+
|
|
8
|
+
export { blockauthRouter, expressSessionStore, sendRouteResponse };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Request, Router, Response } from 'express';
|
|
2
|
+
import { B as BlockAuthRoutes, S as SessionStore, R as RouteResponse } from './routes-DR0gMSlM.js';
|
|
3
|
+
|
|
4
|
+
declare function expressSessionStore(req: Request): SessionStore;
|
|
5
|
+
declare function sendRouteResponse(res: Response, result: RouteResponse): void;
|
|
6
|
+
declare function blockauthRouter(routes: BlockAuthRoutes, session?: (req: Request) => SessionStore): Router;
|
|
7
|
+
|
|
8
|
+
export { blockauthRouter, expressSessionStore, sendRouteResponse };
|
package/dist/express.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
|
|
3
|
+
// src/express.ts
|
|
4
|
+
var MAX_BODY = "64kb";
|
|
5
|
+
function sessionOf(req) {
|
|
6
|
+
const session = req.session;
|
|
7
|
+
if (!session || typeof session.regenerate !== "function") {
|
|
8
|
+
throw new Error("Block-Auth routes need express-session (or a compatible req.session) before blockauthRouter");
|
|
9
|
+
}
|
|
10
|
+
return session;
|
|
11
|
+
}
|
|
12
|
+
function expressSessionStore(req) {
|
|
13
|
+
return {
|
|
14
|
+
get: (key) => sessionOf(req)[key],
|
|
15
|
+
set: (key, value) => {
|
|
16
|
+
sessionOf(req)[key] = value;
|
|
17
|
+
},
|
|
18
|
+
remove: (key) => {
|
|
19
|
+
delete sessionOf(req)[key];
|
|
20
|
+
},
|
|
21
|
+
regenerate: () => new Promise((resolve, reject) => {
|
|
22
|
+
const { cookie: _cookie, regenerate: _regenerate, ...kept } = sessionOf(req);
|
|
23
|
+
sessionOf(req).regenerate((err) => {
|
|
24
|
+
if (err) return reject(err);
|
|
25
|
+
Object.assign(sessionOf(req), kept);
|
|
26
|
+
resolve();
|
|
27
|
+
});
|
|
28
|
+
})
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function rawBodyOf(req, isWebhook) {
|
|
32
|
+
if (Buffer.isBuffer(req.body)) return req.body;
|
|
33
|
+
if (req.body && typeof req.body === "object" && Object.keys(req.body).length > 0) {
|
|
34
|
+
if (isWebhook) {
|
|
35
|
+
throw new Error("Mount blockauthRouter before express.json(): the webhook signature needs the raw body");
|
|
36
|
+
}
|
|
37
|
+
return Buffer.from(JSON.stringify(req.body), "utf8");
|
|
38
|
+
}
|
|
39
|
+
return Buffer.alloc(0);
|
|
40
|
+
}
|
|
41
|
+
function sendRouteResponse(res, result) {
|
|
42
|
+
res.status(result.status).set("Cache-Control", "no-store").json(result.body);
|
|
43
|
+
}
|
|
44
|
+
function blockauthRouter(routes, session = expressSessionStore) {
|
|
45
|
+
const router = express.Router();
|
|
46
|
+
router.use(routes.basePath, express.raw({ type: () => true, limit: MAX_BODY }), async (req, res, next) => {
|
|
47
|
+
try {
|
|
48
|
+
const path = routes.basePath + req.path;
|
|
49
|
+
const rawBody = rawBodyOf(req, path === `${routes.basePath}/webhook`);
|
|
50
|
+
const context = { session: session(req), request: req };
|
|
51
|
+
const result = await routes.dispatch(req.method, path, rawBody, (name) => req.get(name), context);
|
|
52
|
+
if (!result) return next();
|
|
53
|
+
sendRouteResponse(res, result);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
next(err);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return router;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { blockauthRouter, expressSessionStore, sendRouteResponse };
|
|
62
|
+
//# sourceMappingURL=express.js.map
|
|
63
|
+
//# sourceMappingURL=express.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/express.ts"],"names":[],"mappings":"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","file":"express.js","sourcesContent":["import express, { type Request, type Response, type Router } from 'express';\n\nimport { type BlockAuthRoutes, type RouteContext, type RouteResponse, type SessionStore } from './routes';\n\nconst MAX_BODY = '64kb';\n\ntype SessionData = Record<string, unknown> & {\n regenerate(callback: (err?: unknown) => void): void;\n cookie?: unknown;\n};\n\nfunction sessionOf(req: Request): SessionData {\n const session = (req as Request & { session?: SessionData }).session;\n if (!session || typeof session.regenerate !== 'function') {\n throw new Error('Block-Auth routes need express-session (or a compatible req.session) before blockauthRouter');\n }\n return session;\n}\n\nexport function expressSessionStore(req: Request): SessionStore {\n return {\n get: (key) => sessionOf(req)[key],\n set: (key, value) => {\n sessionOf(req)[key] = value;\n },\n remove: (key) => {\n delete sessionOf(req)[key];\n },\n regenerate: () =>\n new Promise<void>((resolve, reject) => {\n const { cookie: _cookie, regenerate: _regenerate, ...kept } = sessionOf(req);\n sessionOf(req).regenerate((err) => {\n if (err) return reject(err);\n Object.assign(sessionOf(req), kept);\n resolve();\n });\n }),\n };\n}\n\nfunction rawBodyOf(req: Request, isWebhook: boolean): Buffer {\n if (Buffer.isBuffer(req.body)) return req.body;\n if (req.body && typeof req.body === 'object' && Object.keys(req.body).length > 0) {\n if (isWebhook) {\n throw new Error('Mount blockauthRouter before express.json(): the webhook signature needs the raw body');\n }\n return Buffer.from(JSON.stringify(req.body), 'utf8');\n }\n return Buffer.alloc(0);\n}\n\nexport function sendRouteResponse(res: Response, result: RouteResponse): void {\n res.status(result.status).set('Cache-Control', 'no-store').json(result.body);\n}\n\nexport function blockauthRouter(\n routes: BlockAuthRoutes,\n session: (req: Request) => SessionStore = expressSessionStore,\n): Router {\n const router = express.Router();\n router.use(routes.basePath, express.raw({ type: () => true, limit: MAX_BODY }), async (req, res, next) => {\n try {\n const path = routes.basePath + req.path;\n const rawBody = rawBodyOf(req, path === `${routes.basePath}/webhook`);\n const context: RouteContext = { session: session(req), request: req };\n const result = await routes.dispatch(req.method, path, rawBody, (name) => req.get(name), context);\n if (!result) return next();\n sendRouteResponse(res, result);\n } catch (err) {\n next(err);\n }\n });\n return router;\n}\n"]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
// src/client.ts
|
|
6
|
+
|
|
7
|
+
// src/errors.ts
|
|
8
|
+
var BlockAuthError = class extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "BlockAuthError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
// src/client.ts
|
|
16
|
+
var DEFAULT_WS_URL = "wss://wss.block-auth.io";
|
|
17
|
+
var DEFAULT_WEBHOOK_MAX_SKEW_SECONDS = 300;
|
|
18
|
+
function sha256Hex(value) {
|
|
19
|
+
return crypto.createHash("sha256").update(value, "utf8").digest("hex");
|
|
20
|
+
}
|
|
21
|
+
function buildWsServerApiUrl(path, wsUrl = "") {
|
|
22
|
+
const url = new URL(wsUrl || DEFAULT_WS_URL);
|
|
23
|
+
const scheme = url.protocol === "wss:" ? "https:" : "http:";
|
|
24
|
+
return `${scheme}//${url.host}/api${path}`;
|
|
25
|
+
}
|
|
26
|
+
var AuthCodeClient = class {
|
|
27
|
+
constructor(apiKey, apiSecret, options = {}) {
|
|
28
|
+
if (!apiKey || !apiSecret) throw new BlockAuthError("apiKey and apiSecret are required");
|
|
29
|
+
this.apiKey = apiKey;
|
|
30
|
+
this.secretHash = sha256Hex(apiSecret);
|
|
31
|
+
this.wsUrl = options.wsUrl ?? "";
|
|
32
|
+
this.timeoutMs = options.timeoutMs ?? 1e4;
|
|
33
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
34
|
+
}
|
|
35
|
+
authorize(redirectUri, state, responseMode) {
|
|
36
|
+
return this.post("/auth/authorize", { redirectUri, state, responseMode });
|
|
37
|
+
}
|
|
38
|
+
exchangeCode(code, redirectUri, codeVerifier, linkExternalId) {
|
|
39
|
+
return this.post("/auth/token", { code, redirectUri, codeVerifier, linkExternalId });
|
|
40
|
+
}
|
|
41
|
+
signOut(address) {
|
|
42
|
+
return this.post("/auth/signout", { address });
|
|
43
|
+
}
|
|
44
|
+
revokeLink(externalId) {
|
|
45
|
+
return this.post("/auth/link/revoke", { externalId });
|
|
46
|
+
}
|
|
47
|
+
verifyWebhook(rawBody, timestamp, signature, maxSkewSeconds = DEFAULT_WEBHOOK_MAX_SKEW_SECONDS) {
|
|
48
|
+
if (!timestamp || !/^\d+$/.test(timestamp)) throw new BlockAuthError("Invalid webhook timestamp");
|
|
49
|
+
if (Math.abs(Date.now() / 1e3 - Number(timestamp)) > maxSkewSeconds) {
|
|
50
|
+
throw new BlockAuthError("Webhook timestamp out of tolerance");
|
|
51
|
+
}
|
|
52
|
+
const body = typeof rawBody === "string" ? Buffer.from(rawBody, "utf8") : rawBody;
|
|
53
|
+
const expected = Buffer.from(
|
|
54
|
+
"v1=" + crypto.createHmac("sha256", this.secretHash).update(Buffer.concat([Buffer.from(`${timestamp}.`, "utf8"), body])).digest("hex"),
|
|
55
|
+
"utf8"
|
|
56
|
+
);
|
|
57
|
+
const provided = Buffer.from(signature ?? "", "utf8");
|
|
58
|
+
if (provided.length !== expected.length || !crypto.timingSafeEqual(provided, expected)) {
|
|
59
|
+
throw new BlockAuthError("Invalid webhook signature");
|
|
60
|
+
}
|
|
61
|
+
let payload;
|
|
62
|
+
try {
|
|
63
|
+
payload = JSON.parse(body.toString("utf8"));
|
|
64
|
+
} catch {
|
|
65
|
+
throw new BlockAuthError("Invalid webhook body");
|
|
66
|
+
}
|
|
67
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
|
68
|
+
throw new BlockAuthError("Invalid webhook body");
|
|
69
|
+
}
|
|
70
|
+
return payload;
|
|
71
|
+
}
|
|
72
|
+
async post(path, params) {
|
|
73
|
+
const body = { apiKey: this.apiKey, apiSecret: this.secretHash };
|
|
74
|
+
for (const [key, value] of Object.entries(params)) {
|
|
75
|
+
if (value !== void 0 && value !== null) body[key] = value;
|
|
76
|
+
}
|
|
77
|
+
let payload;
|
|
78
|
+
try {
|
|
79
|
+
const response = await this.fetchImpl(buildWsServerApiUrl(path, this.wsUrl), {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: { "Content-Type": "application/json" },
|
|
82
|
+
body: JSON.stringify(body),
|
|
83
|
+
redirect: "error",
|
|
84
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
85
|
+
});
|
|
86
|
+
payload = await response.json().catch(() => ({}));
|
|
87
|
+
} catch (error2) {
|
|
88
|
+
throw new BlockAuthError(`Request to ${path} failed: ${error2.message}`);
|
|
89
|
+
}
|
|
90
|
+
if (payload.success !== true) {
|
|
91
|
+
throw new BlockAuthError(
|
|
92
|
+
typeof payload.message === "string" && payload.message ? payload.message : `Request to ${path} failed`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (!payload.message || typeof payload.message !== "object") {
|
|
96
|
+
throw new BlockAuthError(`Unexpected response from ${path}`);
|
|
97
|
+
}
|
|
98
|
+
return payload.message;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/routes.ts
|
|
103
|
+
var DEFAULT_BASE_PATH = "/auth/blockauth";
|
|
104
|
+
var MAX_PARAM_LENGTH = 2048;
|
|
105
|
+
var ROUTE_NAMES = ["code", "me", "logout", "link", "webhook"];
|
|
106
|
+
var LINK_CONFLICTS = [
|
|
107
|
+
"Account already linked",
|
|
108
|
+
"External id already linked",
|
|
109
|
+
"Link conflict"
|
|
110
|
+
];
|
|
111
|
+
var WEBHOOK_EVENTS = ["signout", "account.unlinked"];
|
|
112
|
+
var JSON_POSTS = ["POST /code", "POST /logout", "POST /link"];
|
|
113
|
+
function originOf(url) {
|
|
114
|
+
if (typeof url !== "string") return null;
|
|
115
|
+
let parsed;
|
|
116
|
+
try {
|
|
117
|
+
parsed = new URL(url);
|
|
118
|
+
} catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
if (!["http:", "https:"].includes(parsed.protocol) || !parsed.hostname || parsed.username || parsed.password) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
return parsed.origin;
|
|
125
|
+
}
|
|
126
|
+
function error(status, code) {
|
|
127
|
+
return { status, body: { error: code } };
|
|
128
|
+
}
|
|
129
|
+
function isJson(contentType) {
|
|
130
|
+
return (contentType ?? "").split(";", 1)[0].trim().toLowerCase() === "application/json";
|
|
131
|
+
}
|
|
132
|
+
function parseJson(rawBody) {
|
|
133
|
+
try {
|
|
134
|
+
return JSON.parse(rawBody);
|
|
135
|
+
} catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function publicUser(user) {
|
|
140
|
+
return { address: user.address, did: user.did, roles: user.roles };
|
|
141
|
+
}
|
|
142
|
+
var BlockAuthRoutes = class {
|
|
143
|
+
constructor(options) {
|
|
144
|
+
const origins = options.allowedOrigins ?? (options.appUrl ? [options.appUrl] : []);
|
|
145
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
146
|
+
for (const url of origins) {
|
|
147
|
+
const origin = originOf(url);
|
|
148
|
+
if (!origin)
|
|
149
|
+
throw new BlockAuthError(
|
|
150
|
+
`Invalid origin in appUrl or allowedOrigins: ${String(url)}`
|
|
151
|
+
);
|
|
152
|
+
resolved.add(origin);
|
|
153
|
+
}
|
|
154
|
+
if (resolved.size === 0)
|
|
155
|
+
throw new BlockAuthError(
|
|
156
|
+
"Set appUrl or allowedOrigins: the origins your frontend runs on"
|
|
157
|
+
);
|
|
158
|
+
const unknown = Object.keys(options.routes ?? {}).filter(
|
|
159
|
+
(name) => !ROUTE_NAMES.includes(name)
|
|
160
|
+
);
|
|
161
|
+
if (unknown.length > 0)
|
|
162
|
+
throw new BlockAuthError(`Unknown routes: ${unknown.join(", ")}`);
|
|
163
|
+
this.options = options;
|
|
164
|
+
this.client = options.client ?? new AuthCodeClient(options.apiKey, options.apiSecret, {
|
|
165
|
+
wsUrl: options.wsUrl,
|
|
166
|
+
timeoutMs: options.timeoutMs
|
|
167
|
+
});
|
|
168
|
+
this.allowedOrigins = resolved;
|
|
169
|
+
this.basePath = "/" + (options.basePath ?? DEFAULT_BASE_PATH).replace(/^\/+|\/+$/g, "");
|
|
170
|
+
this.sessionKey = options.sessionKey ?? "blockauth_user";
|
|
171
|
+
this.enabled = {
|
|
172
|
+
code: true,
|
|
173
|
+
me: true,
|
|
174
|
+
logout: true,
|
|
175
|
+
link: true,
|
|
176
|
+
webhook: true,
|
|
177
|
+
...options.routes
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
async currentUser(context) {
|
|
181
|
+
const user = await context.session.get(this.sessionKey);
|
|
182
|
+
const valid = !!user && typeof user === "object" && typeof user.address === "string" && typeof user.expiresAt === "number" && Date.now() / 1e3 < user.expiresAt && !(this.options.isRevoked && await this.options.isRevoked(user));
|
|
183
|
+
if (!valid) {
|
|
184
|
+
if (user != null) await context.session.remove(this.sessionKey);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
return user;
|
|
188
|
+
}
|
|
189
|
+
async code(body, context) {
|
|
190
|
+
const params = this.codeParams(body);
|
|
191
|
+
if (!params) return error(400, "invalid_request");
|
|
192
|
+
let result;
|
|
193
|
+
try {
|
|
194
|
+
result = await this.client.exchangeCode(
|
|
195
|
+
params.code,
|
|
196
|
+
params.redirectUri,
|
|
197
|
+
params.codeVerifier
|
|
198
|
+
);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
this.log("Block-Auth could not redeem the login code", err);
|
|
201
|
+
return error(502, "blockauth_error");
|
|
202
|
+
}
|
|
203
|
+
const expiresAt = this.expiresAt(result.signedExpiredAt);
|
|
204
|
+
if (typeof result.address !== "string" || !result.address || expiresAt === null) {
|
|
205
|
+
this.log("Block-Auth returned a user without address or signedExpiredAt");
|
|
206
|
+
return error(502, "blockauth_error");
|
|
207
|
+
}
|
|
208
|
+
const user = {
|
|
209
|
+
address: result.address,
|
|
210
|
+
did: typeof result.did === "string" && result.did ? result.did : result.address,
|
|
211
|
+
roles: Array.isArray(result.roles) ? result.roles : [],
|
|
212
|
+
externalId: result.externalId ?? null,
|
|
213
|
+
loggedInAt: Math.floor(Date.now() / 1e3),
|
|
214
|
+
expiresAt
|
|
215
|
+
};
|
|
216
|
+
if (this.options.onLogin) {
|
|
217
|
+
const extra = await this.options.onLogin(user, context);
|
|
218
|
+
if (extra === false) {
|
|
219
|
+
await this.client.signOut(user.address).catch(
|
|
220
|
+
(err) => this.log("Block-Auth sign out of a rejected login failed", err)
|
|
221
|
+
);
|
|
222
|
+
return error(403, "forbidden");
|
|
223
|
+
}
|
|
224
|
+
if (extra && typeof extra === "object") user.data = extra;
|
|
225
|
+
}
|
|
226
|
+
await context.session.regenerate();
|
|
227
|
+
await context.session.set(this.sessionKey, user);
|
|
228
|
+
return { status: 200, body: publicUser(user) };
|
|
229
|
+
}
|
|
230
|
+
async me(context) {
|
|
231
|
+
const user = await this.currentUser(context);
|
|
232
|
+
return user ? { status: 200, body: publicUser(user) } : error(401, "unauthenticated");
|
|
233
|
+
}
|
|
234
|
+
async logout(context) {
|
|
235
|
+
const user = await this.currentUser(context);
|
|
236
|
+
if (user) {
|
|
237
|
+
await this.client.signOut(user.address).catch(
|
|
238
|
+
(err) => this.log(
|
|
239
|
+
"Block-Auth sign out failed; the local session is closed anyway",
|
|
240
|
+
err
|
|
241
|
+
)
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
await context.session.remove(this.sessionKey);
|
|
245
|
+
await context.session.regenerate();
|
|
246
|
+
if (user && this.options.onLogout)
|
|
247
|
+
await this.options.onLogout(user, context);
|
|
248
|
+
return { status: 200, body: { ok: true } };
|
|
249
|
+
}
|
|
250
|
+
async linkStatus(context) {
|
|
251
|
+
if (!this.options.appUser) return error(404, "not_found");
|
|
252
|
+
const appUser = await this.resolveAppUser(context);
|
|
253
|
+
return appUser ? { status: 200, body: { linked: appUser.linked === true } } : error(401, "unauthenticated");
|
|
254
|
+
}
|
|
255
|
+
async link(body, context) {
|
|
256
|
+
if (!this.options.appUser) return error(404, "not_found");
|
|
257
|
+
const appUser = await this.resolveAppUser(context);
|
|
258
|
+
if (!appUser) return error(401, "unauthenticated");
|
|
259
|
+
const params = this.codeParams(body);
|
|
260
|
+
if (!params) return error(400, "invalid_request");
|
|
261
|
+
let result;
|
|
262
|
+
try {
|
|
263
|
+
result = await this.client.exchangeCode(
|
|
264
|
+
params.code,
|
|
265
|
+
params.redirectUri,
|
|
266
|
+
params.codeVerifier,
|
|
267
|
+
String(appUser.id)
|
|
268
|
+
);
|
|
269
|
+
} catch (err) {
|
|
270
|
+
if (err instanceof BlockAuthError && LINK_CONFLICTS.includes(err.message))
|
|
271
|
+
return error(409, "already_linked");
|
|
272
|
+
this.log("Block-Auth could not link the account", err);
|
|
273
|
+
return error(502, "blockauth_error");
|
|
274
|
+
}
|
|
275
|
+
if (this.options.onLinked)
|
|
276
|
+
await this.options.onLinked(appUser.id, result, context);
|
|
277
|
+
return { status: 200, body: { linked: true } };
|
|
278
|
+
}
|
|
279
|
+
async webhook(rawBody, timestamp, signature) {
|
|
280
|
+
let event;
|
|
281
|
+
try {
|
|
282
|
+
event = this.client.verifyWebhook(
|
|
283
|
+
rawBody,
|
|
284
|
+
timestamp,
|
|
285
|
+
signature,
|
|
286
|
+
this.options.webhookMaxSkewSeconds
|
|
287
|
+
);
|
|
288
|
+
} catch (err) {
|
|
289
|
+
this.log("Rejected a webhook that failed verification", err);
|
|
290
|
+
return error(401, "invalid_signature");
|
|
291
|
+
}
|
|
292
|
+
if (event.apiKey !== this.options.apiKey)
|
|
293
|
+
return error(401, "invalid_signature");
|
|
294
|
+
if (!WEBHOOK_EVENTS.includes(event.event) || typeof event.address !== "string") {
|
|
295
|
+
return { status: 200, body: { ok: true, ignored: true } };
|
|
296
|
+
}
|
|
297
|
+
if (this.options.isReplay && (typeof event.jti !== "string" || await this.options.isReplay(event.jti, event))) {
|
|
298
|
+
return error(409, "replayed");
|
|
299
|
+
}
|
|
300
|
+
const handler = event.event === "signout" ? this.options.onSignout : this.options.onUnlinked;
|
|
301
|
+
if (handler) await handler(event);
|
|
302
|
+
return { status: 200, body: { ok: true } };
|
|
303
|
+
}
|
|
304
|
+
async dispatch(method, path, rawBody, header, context) {
|
|
305
|
+
if (!path.startsWith(this.basePath + "/")) return null;
|
|
306
|
+
const route = `${method.toUpperCase()} ${path.slice(this.basePath.length)}`;
|
|
307
|
+
const name = {
|
|
308
|
+
"POST /code": "code",
|
|
309
|
+
"GET /me": "me",
|
|
310
|
+
"POST /logout": "logout",
|
|
311
|
+
"GET /link": "link",
|
|
312
|
+
"POST /link": "link",
|
|
313
|
+
"POST /webhook": "webhook"
|
|
314
|
+
}[route];
|
|
315
|
+
if (!name || !this.enabled[name]) return null;
|
|
316
|
+
if (JSON_POSTS.includes(route) && !isJson(header("content-type")))
|
|
317
|
+
return error(415, "unsupported_media_type");
|
|
318
|
+
const text = typeof rawBody === "string" ? rawBody : rawBody.toString("utf8");
|
|
319
|
+
switch (route) {
|
|
320
|
+
case "POST /code":
|
|
321
|
+
return this.code(parseJson(text), context);
|
|
322
|
+
case "GET /me":
|
|
323
|
+
return this.me(context);
|
|
324
|
+
case "POST /logout":
|
|
325
|
+
return this.logout(context);
|
|
326
|
+
case "GET /link":
|
|
327
|
+
return this.linkStatus(context);
|
|
328
|
+
case "POST /link":
|
|
329
|
+
return this.link(parseJson(text), context);
|
|
330
|
+
default:
|
|
331
|
+
return this.webhook(
|
|
332
|
+
rawBody,
|
|
333
|
+
header("x-blockauth-timestamp"),
|
|
334
|
+
header("x-blockauth-signature")
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
codeParams(body) {
|
|
339
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return null;
|
|
340
|
+
const { code, codeVerifier, redirectUri } = body;
|
|
341
|
+
for (const value of [code, codeVerifier, redirectUri]) {
|
|
342
|
+
if (typeof value !== "string" || !value || value.length > MAX_PARAM_LENGTH)
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
const origin = originOf(redirectUri);
|
|
346
|
+
if (!origin || !this.allowedOrigins.has(origin)) return null;
|
|
347
|
+
return {
|
|
348
|
+
code,
|
|
349
|
+
codeVerifier,
|
|
350
|
+
redirectUri
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
expiresAt(signedExpiredAt) {
|
|
354
|
+
if (typeof signedExpiredAt !== "string") return null;
|
|
355
|
+
const match = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/.exec(
|
|
356
|
+
signedExpiredAt
|
|
357
|
+
);
|
|
358
|
+
if (!match) return null;
|
|
359
|
+
const [year, month, day, hour, minute, second] = match.slice(1).map(Number);
|
|
360
|
+
let expiresAt = Date.UTC(year, month - 1, day, hour, minute, second) / 1e3;
|
|
361
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
362
|
+
if (this.options.maxSessionSeconds !== void 0) {
|
|
363
|
+
expiresAt = Math.min(
|
|
364
|
+
expiresAt,
|
|
365
|
+
now + Math.max(1, Math.floor(this.options.maxSessionSeconds))
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
return Number.isFinite(expiresAt) && expiresAt > now ? expiresAt : null;
|
|
369
|
+
}
|
|
370
|
+
async resolveAppUser(context) {
|
|
371
|
+
const appUser = await this.options.appUser?.(context);
|
|
372
|
+
if (!appUser || typeof appUser !== "object") return null;
|
|
373
|
+
const { id } = appUser;
|
|
374
|
+
if (!(typeof id === "string" && id || typeof id === "number" && Number.isFinite(id)))
|
|
375
|
+
return null;
|
|
376
|
+
return appUser;
|
|
377
|
+
}
|
|
378
|
+
log(message, err) {
|
|
379
|
+
this.options.logger?.(message, err);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
exports.AuthCodeClient = AuthCodeClient;
|
|
384
|
+
exports.BlockAuthError = BlockAuthError;
|
|
385
|
+
exports.BlockAuthRoutes = BlockAuthRoutes;
|
|
386
|
+
exports.DEFAULT_BASE_PATH = DEFAULT_BASE_PATH;
|
|
387
|
+
exports.DEFAULT_WS_URL = DEFAULT_WS_URL;
|
|
388
|
+
exports.buildWsServerApiUrl = buildWsServerApiUrl;
|
|
389
|
+
exports.sha256Hex = sha256Hex;
|
|
390
|
+
//# sourceMappingURL=index.cjs.map
|
|
391
|
+
//# sourceMappingURL=index.cjs.map
|