@ruiapp/rapid-core 0.5.7 → 0.5.8

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/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from "./core/server";
6
6
  export * from "./core/http-types";
7
7
  export * from "./core/actionHandler";
8
8
  export * from "./utilities/jwtUtility";
9
+ export * from "./deno-std/http/cookie";
9
10
  export { mapDbRowToEntity } from "./dataAccess/entityMapper";
10
11
  export * as bootstrapApplicationConfig from "./bootstrapApplicationConfig";
11
12
  export { default as MetaManagePlugin } from "./plugins/metaManage/MetaManagePlugin";
package/dist/index.js CHANGED
@@ -1402,6 +1402,130 @@ function setCookie(headers, cookie) {
1402
1402
  if (v) {
1403
1403
  headers.append("Set-Cookie", v);
1404
1404
  }
1405
+ }
1406
+ /**
1407
+ * Set the cookie header with empty value in the headers to delete it
1408
+ *
1409
+ * > Note: Deleting a `Cookie` will set its expiration date before now. Forcing
1410
+ * > the browser to delete it.
1411
+ *
1412
+ * @example
1413
+ * ```ts
1414
+ * import { deleteCookie } from "https://deno.land/std@$STD_VERSION/http/cookie.ts";
1415
+ *
1416
+ * const headers = new Headers();
1417
+ * deleteCookie(headers, "deno");
1418
+ *
1419
+ * const cookieHeader = headers.get("set-cookie");
1420
+ * console.log(cookieHeader); // deno=; Expires=Thus, 01 Jan 1970 00:00:00 GMT
1421
+ * ```
1422
+ *
1423
+ * @param headers The headers instance to delete the cookie from
1424
+ * @param name Name of cookie
1425
+ * @param attributes Additional cookie attributes
1426
+ */
1427
+ function deleteCookie(headers, name, attributes) {
1428
+ setCookie(headers, {
1429
+ name: name,
1430
+ value: "",
1431
+ expires: new Date(0),
1432
+ ...attributes,
1433
+ });
1434
+ }
1435
+ function parseSetCookie(value) {
1436
+ const attrs = value.split(";").map((attr) => {
1437
+ const [key, ...values] = attr.trim().split("=");
1438
+ return [key, values.join("=")];
1439
+ });
1440
+ const cookie = {
1441
+ name: attrs[0][0],
1442
+ value: attrs[0][1],
1443
+ };
1444
+ for (const [key, value] of attrs.slice(1)) {
1445
+ switch (key.toLocaleLowerCase()) {
1446
+ case "expires":
1447
+ cookie.expires = new Date(value);
1448
+ break;
1449
+ case "max-age":
1450
+ cookie.maxAge = Number(value);
1451
+ if (cookie.maxAge < 0) {
1452
+ console.warn("Max-Age must be an integer superior or equal to 0. Cookie ignored.");
1453
+ return null;
1454
+ }
1455
+ break;
1456
+ case "domain":
1457
+ cookie.domain = value;
1458
+ break;
1459
+ case "path":
1460
+ cookie.path = value;
1461
+ break;
1462
+ case "secure":
1463
+ cookie.secure = true;
1464
+ break;
1465
+ case "httponly":
1466
+ cookie.httpOnly = true;
1467
+ break;
1468
+ case "samesite":
1469
+ cookie.sameSite = value;
1470
+ break;
1471
+ default:
1472
+ if (!Array.isArray(cookie.unparsed)) {
1473
+ cookie.unparsed = [];
1474
+ }
1475
+ cookie.unparsed.push([key, value].join("="));
1476
+ }
1477
+ }
1478
+ if (cookie.name.startsWith("__Secure-")) {
1479
+ /** This requirement is mentioned in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie but not the RFC. */
1480
+ if (!cookie.secure) {
1481
+ console.warn("Cookies with names starting with `__Secure-` must be set with the secure flag. Cookie ignored.");
1482
+ return null;
1483
+ }
1484
+ }
1485
+ if (cookie.name.startsWith("__Host-")) {
1486
+ if (!cookie.secure) {
1487
+ console.warn("Cookies with names starting with `__Host-` must be set with the secure flag. Cookie ignored.");
1488
+ return null;
1489
+ }
1490
+ if (cookie.domain !== undefined) {
1491
+ console.warn("Cookies with names starting with `__Host-` must not have a domain specified. Cookie ignored.");
1492
+ return null;
1493
+ }
1494
+ if (cookie.path !== "/") {
1495
+ console.warn("Cookies with names starting with `__Host-` must have path be `/`. Cookie has been ignored.");
1496
+ return null;
1497
+ }
1498
+ }
1499
+ return cookie;
1500
+ }
1501
+ /**
1502
+ * Parse set-cookies of a header
1503
+ *
1504
+ * @example
1505
+ * ```ts
1506
+ * import { getSetCookies } from "https://deno.land/std@$STD_VERSION/http/cookie.ts";
1507
+ *
1508
+ * const headers = new Headers([
1509
+ * ["Set-Cookie", "lulu=meow; Secure; Max-Age=3600"],
1510
+ * ["Set-Cookie", "booya=kasha; HttpOnly; Path=/"],
1511
+ * ]);
1512
+ *
1513
+ * const cookies = getSetCookies(headers);
1514
+ * console.log(cookies); // [{ name: "lulu", value: "meow", secure: true, maxAge: 3600 }, { name: "booya", value: "kahsa", httpOnly: true, path: "/ }]
1515
+ * ```
1516
+ *
1517
+ * @param headers The headers instance to get set-cookies from
1518
+ * @return List of cookies
1519
+ */
1520
+ function getSetCookies(headers) {
1521
+ // TODO(lino-levan): remove this ts-ignore when Typescript 5.2 lands in Deno
1522
+ // @ts-ignore Typescript's TS Dom types will be out of date until 5.2
1523
+ return headers
1524
+ .getSetCookie()
1525
+ /** Parse each `set-cookie` header separately */
1526
+ .map(parseSetCookie)
1527
+ /** Skip empty cookies */
1528
+ .filter(Boolean);
1405
1529
  }
1406
1530
 
1407
1531
  const GlobalRequest = global.Request;
@@ -6298,14 +6422,12 @@ async function handler$d(plugin, ctx, options) {
6298
6422
  if (!isMatch) {
6299
6423
  throw new Error("用户名或密码错误。");
6300
6424
  }
6301
- const secretKey = Buffer.from(server.config.jwtKey, "base64");
6302
- const token = createJwt({
6303
- iss: "authManager",
6304
- sub: "userAccessToken",
6305
- aud: "" + user.id,
6306
- iat: Math.floor(Date.now() / 1000),
6307
- act: user.login,
6308
- }, secretKey);
6425
+ const authService = server.getService("authService");
6426
+ const token = authService.createUserAccessToken({
6427
+ issuer: "authManager",
6428
+ userId: user.id,
6429
+ userLogin: user.login,
6430
+ });
6309
6431
  setCookie(response.headers, {
6310
6432
  name: ctx.server.config.sessionCookieName,
6311
6433
  value: token,
@@ -6539,10 +6661,31 @@ var signout$1 = {
6539
6661
 
6540
6662
  var pluginRoutes$7 = [changePassword, getMyProfile$1, resetPassword, signin$1, signout$1];
6541
6663
 
6664
+ class AuthService {
6665
+ #server;
6666
+ #jwtKey;
6667
+ constructor(server, jwtKey) {
6668
+ this.#server = server;
6669
+ this.#jwtKey = jwtKey;
6670
+ }
6671
+ createUserAccessToken(options) {
6672
+ const secretKey = Buffer.from(this.#jwtKey, "base64");
6673
+ const token = createJwt({
6674
+ iss: options.issuer,
6675
+ sub: "userAccessToken",
6676
+ aud: "" + options.userId,
6677
+ iat: Math.floor(Date.now() / 1000),
6678
+ act: options.userLogin,
6679
+ }, secretKey);
6680
+ return token;
6681
+ }
6682
+ }
6683
+
6542
6684
  /**
6543
6685
  * Auth manager plugin
6544
6686
  */
6545
6687
  class AuthPlugin {
6688
+ #authService;
6546
6689
  get code() {
6547
6690
  return "authManager";
6548
6691
  }
@@ -6566,6 +6709,10 @@ class AuthPlugin {
6566
6709
  async configureModels(server, applicationConfig) {
6567
6710
  server.appendApplicationConfig({ models: pluginModels$5 });
6568
6711
  }
6712
+ async configureServices(server, applicationConfig) {
6713
+ this.#authService = new AuthService(server, server.config.jwtKey);
6714
+ server.registerService("authService", this.#authService);
6715
+ }
6569
6716
  async configureRoutes(server, applicationConfig) {
6570
6717
  server.appendApplicationConfig({ routes: pluginRoutes$7 });
6571
6718
  }
@@ -8549,6 +8696,10 @@ exports.WebhooksPlugin = WebhooksPlugin;
8549
8696
  exports.bootstrapApplicationConfig = bootstrapApplicationConfig$1;
8550
8697
  exports.createJwt = createJwt;
8551
8698
  exports.decodeJwt = decodeJwt;
8699
+ exports.deleteCookie = deleteCookie;
8552
8700
  exports.generateJwtSecretKey = generateJwtSecretKey;
8701
+ exports.getCookies = getCookies;
8702
+ exports.getSetCookies = getSetCookies;
8553
8703
  exports.mapDbRowToEntity = mapDbRowToEntity;
8704
+ exports.setCookie = setCookie;
8554
8705
  exports.verifyJwt = verifyJwt;
@@ -5,6 +5,7 @@ import { RpdApplicationConfig } from "../../types";
5
5
  import { IRpdServer, RapidPlugin, RpdConfigurationItemOptions, RpdServerPluginConfigurableTargetOptions, RpdServerPluginExtendingAbilities } from "../../core/server";
6
6
  import { RouteContext } from "../../core/routeContext";
7
7
  declare class AuthPlugin implements RapidPlugin {
8
+ #private;
8
9
  get code(): string;
9
10
  get description(): string;
10
11
  get extendingAbilities(): RpdServerPluginExtendingAbilities[];
@@ -12,6 +13,7 @@ declare class AuthPlugin implements RapidPlugin {
12
13
  get configurations(): RpdConfigurationItemOptions[];
13
14
  registerActionHandlers(server: IRpdServer): Promise<any>;
14
15
  configureModels(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any>;
16
+ configureServices(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any>;
15
17
  configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any>;
16
18
  onPrepareRouteContext(server: IRpdServer, routeContext: RouteContext): Promise<void>;
17
19
  }
@@ -1,8 +1,4 @@
1
1
  import { ActionHandlerContext } from "../../../core/actionHandler";
2
2
  import { RapidPlugin } from "../../../core/server";
3
- export interface UserAccessToken {
4
- sub: "userAccessToken";
5
- aud: string;
6
- }
7
3
  export declare const code = "createSession";
8
4
  export declare function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, options: any): Promise<void>;
@@ -0,0 +1,15 @@
1
+ import { IRpdServer } from "../../../core/server";
2
+ export interface UserAccessToken {
3
+ sub: "userAccessToken";
4
+ aud: string;
5
+ }
6
+ export interface CreateUserAccessTokenOptions {
7
+ issuer: string;
8
+ userId: number;
9
+ userLogin: string;
10
+ }
11
+ export default class AuthService {
12
+ #private;
13
+ constructor(server: IRpdServer, jwtKey: string);
14
+ createUserAccessToken(options: CreateUserAccessTokenOptions): string;
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -12,6 +12,8 @@ export * from "./core/actionHandler";
12
12
 
13
13
  export * from "./utilities/jwtUtility";
14
14
 
15
+ export * from "./deno-std/http/cookie";
16
+
15
17
  export { mapDbRowToEntity } from "./dataAccess/entityMapper";
16
18
 
17
19
  export * as bootstrapApplicationConfig from "./bootstrapApplicationConfig";
@@ -16,8 +16,11 @@ import pluginModels from "./models";
16
16
  import pluginRoutes from "./routes";
17
17
  import { RouteContext } from "~/core/routeContext";
18
18
  import { verifyJwt } from "~/utilities/jwtUtility";
19
+ import AuthService from "./services/AuthService";
19
20
 
20
21
  class AuthPlugin implements RapidPlugin {
22
+ #authService!: AuthService;
23
+
21
24
  get code(): string {
22
25
  return "authManager";
23
26
  }
@@ -48,6 +51,11 @@ class AuthPlugin implements RapidPlugin {
48
51
  server.appendApplicationConfig({ models: pluginModels });
49
52
  }
50
53
 
54
+ async configureServices(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
55
+ this.#authService = new AuthService(server, server.config.jwtKey);
56
+ server.registerService("authService", this.#authService);
57
+ }
58
+
51
59
  async configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
52
60
  server.appendApplicationConfig({ routes: pluginRoutes });
53
61
  }
@@ -1,15 +1,10 @@
1
1
  import bcrypt from "bcrypt";
2
2
  import { setCookie } from "~/deno-std/http/cookie";
3
- import { createJwt } from "~/utilities/jwtUtility";
4
3
  import { ActionHandlerContext } from "~/core/actionHandler";
5
4
  import { RapidPlugin } from "~/core/server";
6
5
  import LicenseService from "~/plugins/license/LicenseService";
7
6
  import { get } from "lodash";
8
-
9
- export interface UserAccessToken {
10
- sub: "userAccessToken";
11
- aud: string;
12
- }
7
+ import AuthService from "../services/AuthService";
13
8
 
14
9
  export const code = "createSession";
15
10
 
@@ -54,17 +49,12 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
54
49
  throw new Error("用户名或密码错误。");
55
50
  }
56
51
 
57
- const secretKey = Buffer.from(server.config.jwtKey, "base64");
58
- const token = createJwt(
59
- {
60
- iss: "authManager",
61
- sub: "userAccessToken",
62
- aud: "" + user.id,
63
- iat: Math.floor(Date.now() / 1000),
64
- act: user.login,
65
- } as UserAccessToken,
66
- secretKey,
67
- );
52
+ const authService = server.getService<AuthService>("authService");
53
+ const token = authService.createUserAccessToken({
54
+ issuer: "authManager",
55
+ userId: user.id,
56
+ userLogin: user.login,
57
+ });
68
58
 
69
59
  setCookie(response.headers, {
70
60
  name: ctx.server.config.sessionCookieName,
@@ -0,0 +1,39 @@
1
+ import { IRpdServer } from "~/core/server";
2
+ import { createJwt } from "~/utilities/jwtUtility";
3
+
4
+ export interface UserAccessToken {
5
+ sub: "userAccessToken";
6
+ aud: string;
7
+ }
8
+
9
+ export interface CreateUserAccessTokenOptions {
10
+ issuer: string;
11
+ userId: number;
12
+ userLogin: string;
13
+ }
14
+
15
+ export default class AuthService {
16
+ #server: IRpdServer;
17
+ #jwtKey: string;
18
+
19
+ constructor(server: IRpdServer, jwtKey: string) {
20
+ this.#server = server;
21
+ this.#jwtKey = jwtKey;
22
+ }
23
+
24
+ createUserAccessToken(options: CreateUserAccessTokenOptions): string {
25
+ const secretKey = Buffer.from(this.#jwtKey, "base64");
26
+ const token = createJwt(
27
+ {
28
+ iss: options.issuer,
29
+ sub: "userAccessToken",
30
+ aud: "" + options.userId,
31
+ iat: Math.floor(Date.now() / 1000),
32
+ act: options.userLogin,
33
+ } as UserAccessToken,
34
+ secretKey,
35
+ );
36
+
37
+ return token;
38
+ }
39
+ }