@opengis/fastify-table 2.1.13 → 2.1.15
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/dist/server/plugins/auth/funcs/jwt.d.ts +5 -2
- package/dist/server/plugins/auth/funcs/jwt.d.ts.map +1 -1
- package/dist/server/plugins/auth/funcs/jwt.js +16 -13
- package/dist/server/plugins/policy/funcs/checkPermissions.js +1 -1
- package/dist/server/routes/auth/controllers/jwt/authorize.js +2 -2
- package/dist/server/routes/auth/controllers/jwt/token.js +2 -2
- package/dist/server/routes/table/functions/getData.d.ts.map +1 -1
- package/dist/server/routes/table/functions/getData.js +5 -1
- package/package.json +1 -1
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
export declare function scryptHash(code: string): Promise<string>;
|
|
2
2
|
export declare function scryptVerify(stored: string, code: string): Promise<boolean>;
|
|
3
|
-
export declare function sign(uid: string, secret
|
|
4
|
-
export declare function verify(token: string, secret
|
|
3
|
+
export declare function sign(uid: string, secret: string, exp: number | undefined, ip: string): string;
|
|
4
|
+
export declare function verify(token: string, secret: string, ip: string): false | {
|
|
5
|
+
payload: any;
|
|
6
|
+
header: any;
|
|
7
|
+
};
|
|
5
8
|
declare const _default: null;
|
|
6
9
|
export default _default;
|
|
7
10
|
//# sourceMappingURL=jwt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/auth/funcs/jwt.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"jwt.d.ts","sourceRoot":"","sources":["../../../../../server/plugins/auth/funcs/jwt.ts"],"names":[],"mappings":"AAmBA,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,mBAI5C;AAED,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,oBAI9D;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,oBAAQ,EAAE,EAAE,EAAE,MAAM,UAsBxE;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;;EA8B/D;;AAED,wBAAoB"}
|
|
@@ -5,7 +5,7 @@ const scryptAsync = util.promisify(scrypt);
|
|
|
5
5
|
const { jwtSecret = "65450754381cfaf768eeb4bb33326529b48a40ffdb6e15d84dc224dff527166f", } = config.auth || {};
|
|
6
6
|
const jwtHeader = Buffer.from(JSON.stringify({
|
|
7
7
|
alg: "HS256",
|
|
8
|
-
|
|
8
|
+
type: "JWT",
|
|
9
9
|
})).toString("base64");
|
|
10
10
|
export async function scryptHash(code) {
|
|
11
11
|
const salt = randomBytes(16).toString("hex");
|
|
@@ -17,42 +17,45 @@ export async function scryptVerify(stored, code) {
|
|
|
17
17
|
const derived = (await scryptAsync(code, salt, 64));
|
|
18
18
|
return keyHex === derived.toString("hex");
|
|
19
19
|
}
|
|
20
|
-
export function sign(uid, secret
|
|
20
|
+
export function sign(uid, secret, exp = 90000, ip) {
|
|
21
21
|
if (typeof uid !== "string")
|
|
22
22
|
throw new Error("uid must be a string");
|
|
23
|
-
if (secret && typeof secret !== "string")
|
|
23
|
+
if (secret && typeof secret !== "string") {
|
|
24
24
|
throw new Error("secret must be a string");
|
|
25
|
+
}
|
|
25
26
|
if (typeof exp !== "number")
|
|
26
27
|
throw new Error("exp must be a number");
|
|
27
28
|
const jwtPayload = Buffer.from(JSON.stringify({
|
|
29
|
+
ip,
|
|
28
30
|
uid,
|
|
29
|
-
exp,
|
|
31
|
+
expires: Date.now() + exp,
|
|
30
32
|
created: Date.now(),
|
|
31
33
|
})).toString("base64");
|
|
32
34
|
const jwtEncrypted = [jwtHeader, jwtPayload].join(".");
|
|
33
|
-
const signature = createHmac("sha256", secret)
|
|
35
|
+
const signature = createHmac("sha256", secret || jwtSecret)
|
|
34
36
|
.update(jwtEncrypted)
|
|
35
37
|
.digest("base64");
|
|
36
38
|
return `${jwtEncrypted}.${signature}`;
|
|
37
39
|
}
|
|
38
|
-
export function verify(token, secret
|
|
40
|
+
export function verify(token, secret, ip) {
|
|
39
41
|
if (!token)
|
|
40
42
|
throw new Error("not enough params: token");
|
|
41
|
-
if (
|
|
43
|
+
if (secret && typeof secret !== "string") {
|
|
42
44
|
throw new Error("not enough params: secret");
|
|
45
|
+
}
|
|
43
46
|
const split = token.split(".");
|
|
44
47
|
const signature = split[2];
|
|
45
48
|
try {
|
|
46
49
|
const header = JSON.parse(Buffer.from(split[0], "base64").toString());
|
|
47
50
|
const payload = JSON.parse(Buffer.from(split[1], "base64").toString());
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const jwtEncryptedExpected = [jwtHeader, jwtPayload].join(".");
|
|
51
|
-
const expectedSignature = createHmac("sha256", secret)
|
|
51
|
+
const jwtEncryptedExpected = [split[0], split[1]].join(".");
|
|
52
|
+
const expectedSignature = createHmac("sha256", secret || jwtSecret)
|
|
52
53
|
.update(jwtEncryptedExpected)
|
|
53
54
|
.digest("base64");
|
|
54
|
-
if (signature === expectedSignature
|
|
55
|
-
|
|
55
|
+
if (signature === expectedSignature &&
|
|
56
|
+
payload.expires > Date.now() &&
|
|
57
|
+
payload.ip === ip) {
|
|
58
|
+
return { payload, header };
|
|
56
59
|
}
|
|
57
60
|
return false;
|
|
58
61
|
}
|
|
@@ -21,7 +21,7 @@ export default async function checkPermissions(req) {
|
|
|
21
21
|
permissions?.length &&
|
|
22
22
|
permissions.length ===
|
|
23
23
|
permissions.filter(([key, value]) => userPermissions[key]?.includes(value)).length;
|
|
24
|
-
if (!havePermission) {
|
|
24
|
+
if (!user?.user_type?.includes?.("admin") && !havePermission) {
|
|
25
25
|
logger.file("policy/permissions", {
|
|
26
26
|
path,
|
|
27
27
|
method,
|
|
@@ -52,10 +52,10 @@ export default async function authorize(req, reply) {
|
|
|
52
52
|
return reply.code(404).send({ error: "user not found", code: 404 });
|
|
53
53
|
}
|
|
54
54
|
const href1 = await authorizeUser(user, req, "jwt", expireMsec);
|
|
55
|
+
const ip = getIp(req);
|
|
55
56
|
// Generate authorization code
|
|
56
|
-
const code = sign(userId, secret, expireMsec);
|
|
57
|
+
const code = sign(userId, secret, expireMsec, ip);
|
|
57
58
|
const tokenHash = await scryptHash(code);
|
|
58
|
-
const ip = getIp(req);
|
|
59
59
|
// disable access via old tokens
|
|
60
60
|
if (pg.pk?.["oauth.tokens"]) {
|
|
61
61
|
await pg.query("update oauth.tokens set revoked_at = now(), revocation_reason='refresh' where client_id=$1", [client_id]);
|
|
@@ -32,10 +32,10 @@ export default async function oauthToken(req, reply) {
|
|
|
32
32
|
.query(q, [client_id, "private_key_jwt"])
|
|
33
33
|
.then((el) => el.rows?.[0] || {})
|
|
34
34
|
: {};
|
|
35
|
-
const
|
|
35
|
+
const ip = getIp(req);
|
|
36
|
+
const isCodeValid = verify(code, secret, ip);
|
|
36
37
|
const q1 = "select token_hash, expires_at, ip from oauth.tokens where client_id=$1 and revoked_at is null and expires_at > now()";
|
|
37
38
|
const { token_hash: stored, expires_at, ip: storedIp, } = await pg.query(q1, [client_id]).then((el) => el.rows?.[0] || {});
|
|
38
|
-
const ip = getIp(req);
|
|
39
39
|
if (storedIp !== ip) {
|
|
40
40
|
return reply
|
|
41
41
|
.code(403)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getData.d.ts","sourceRoot":"","sources":["../../../../../server/routes/table/functions/getData.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkFzD,wBAA8B,OAAO,CACnC,EACE,EAAqB,EACrB,MAAM,EACN,KAAK,EACL,EAAE,EACF,OAAY,EACZ,KAAU,EACV,IAAS,EACT,YAAY,EACZ,YAAY,EACZ,KAAY,EACZ,UAAU,EACV,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,YAAY,EACrB,QAAgB,GACjB,EAAE;IACD,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,EACD,MAAM,CAAC,EAAE,YAAY,EACrB,MAAM,CAAC,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"getData.d.ts","sourceRoot":"","sources":["../../../../../server/routes/table/functions/getData.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAkFzD,wBAA8B,OAAO,CACnC,EACE,EAAqB,EACrB,MAAM,EACN,KAAK,EACL,EAAE,EACF,OAAY,EACZ,KAAU,EACV,IAAS,EACT,YAAY,EACZ,YAAY,EACZ,KAAY,EACZ,UAAU,EACV,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,YAAY,EACrB,QAAgB,GACjB,EAAE;IACD,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,EACD,MAAM,CAAC,EAAE,YAAY,EACrB,MAAM,CAAC,EAAE,GAAG,gBAk3Bb"}
|
|
@@ -163,7 +163,11 @@ export default async function dataAPI({ pg = pgClients.client, params, table, id
|
|
|
163
163
|
tokenData?.public ||
|
|
164
164
|
params?.public ||
|
|
165
165
|
false;
|
|
166
|
-
if (!ispublic &&
|
|
166
|
+
if (!ispublic &&
|
|
167
|
+
!user?.uid &&
|
|
168
|
+
!called &&
|
|
169
|
+
!accessQueryParam &&
|
|
170
|
+
!actionsParam) {
|
|
167
171
|
return reply.status(401).send({ error: "unauthorized", code: 401 });
|
|
168
172
|
}
|
|
169
173
|
if (!ispublic && !actions.includes("view") && !config?.local && !called) {
|