jcc-express-mvc 1.8.8 → 1.8.21
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/__tests__/MySqlSchemaBlueprint.test.d.ts +2 -0
- package/__tests__/MySqlSchemaBlueprint.test.d.ts.map +1 -0
- package/__tests__/MySqlSchemaBlueprint.test.js +55 -0
- package/__tests__/PostgresTranslator.test.d.ts +2 -0
- package/__tests__/PostgresTranslator.test.d.ts.map +1 -0
- package/__tests__/PostgresTranslator.test.js +82 -0
- package/__tests__/SQLiteTranslator.test.d.ts +2 -0
- package/__tests__/SQLiteTranslator.test.d.ts.map +1 -0
- package/__tests__/SQLiteTranslator.test.js +125 -0
- package/__tests__/SchemaAlterBlueprint.test.d.ts +2 -0
- package/__tests__/SchemaAlterBlueprint.test.d.ts.map +1 -0
- package/__tests__/SchemaAlterBlueprint.test.js +35 -0
- package/global.d.ts +3 -1
- package/index.d.ts +28 -3
- package/index.d.ts.map +1 -1
- package/index.js +33 -75
- package/lib/Application/Application.d.ts +1 -1
- package/lib/Application/Application.d.ts.map +1 -1
- package/lib/Application/Application.js +2 -2
- package/lib/Application/ApplicationBuilder.d.ts.map +1 -1
- package/lib/Application/ApplicationBuilder.js +9 -2
- package/lib/Auth/AuthMiddleware.d.ts.map +1 -1
- package/lib/Auth/AuthMiddleware.js +29 -12
- package/lib/Auth/index.d.ts +17 -3
- package/lib/Auth/index.d.ts.map +1 -1
- package/lib/Auth/index.js +128 -26
- package/lib/Auth/loginRateLimit.d.ts +6 -0
- package/lib/Auth/loginRateLimit.d.ts.map +1 -0
- package/lib/Auth/loginRateLimit.js +25 -0
- package/lib/Auth/refreshTokenStore.d.ts +24 -0
- package/lib/Auth/refreshTokenStore.d.ts.map +1 -0
- package/lib/Auth/refreshTokenStore.js +46 -0
- package/lib/Command-Line/DBCommand.d.ts.map +1 -1
- package/lib/Command-Line/DBCommand.js +9 -3
- package/lib/Command-Line/KeyGenerateCommand.d.ts +6 -0
- package/lib/Command-Line/KeyGenerateCommand.d.ts.map +1 -0
- package/lib/Command-Line/KeyGenerateCommand.js +47 -0
- package/lib/Command-Line/NodeArtisanCommand.d.ts +2 -0
- package/lib/Command-Line/NodeArtisanCommand.d.ts.map +1 -1
- package/lib/Command-Line/NodeArtisanCommand.js +20 -3
- package/lib/Command-Line/NodeTinker/Tinker.d.ts +5 -2
- package/lib/Command-Line/NodeTinker/Tinker.d.ts.map +1 -1
- package/lib/Command-Line/NodeTinker/Tinker.js +13 -3
- package/lib/Command-Line/WatchCommand.d.ts +29 -0
- package/lib/Command-Line/WatchCommand.d.ts.map +1 -0
- package/lib/Command-Line/WatchCommand.js +234 -0
- package/lib/Command-Line/files/Models.d.ts.map +1 -1
- package/lib/Command-Line/files/Models.js +41 -16
- package/lib/Console/Command.d.ts +18 -0
- package/lib/Console/Command.d.ts.map +1 -1
- package/lib/Console/Command.js +29 -0
- package/lib/Container/index.d.ts.map +1 -1
- package/lib/Container/index.js +21 -7
- package/lib/Database/Database.d.ts +2 -1
- package/lib/Database/Database.d.ts.map +1 -1
- package/lib/Database/Database.js +6 -5
- package/lib/Database/DatabaseServiceProvider.d.ts +0 -4
- package/lib/Database/DatabaseServiceProvider.d.ts.map +1 -1
- package/lib/Database/DatabaseServiceProvider.js +9 -56
- package/lib/Database/Drivers/MongooseDriver.d.ts +2 -0
- package/lib/Database/Drivers/MongooseDriver.d.ts.map +1 -1
- package/lib/Database/Drivers/MongooseDriver.js +11 -13
- package/lib/Database/Drivers/SequelizeDriver.d.ts +9 -1
- package/lib/Database/Drivers/SequelizeDriver.d.ts.map +1 -1
- package/lib/Database/Drivers/SequelizeDriver.js +43 -18
- package/lib/Error/SocialiteAuthError/SocialiteAuthError.d.ts +9 -0
- package/lib/Error/SocialiteAuthError/SocialiteAuthError.d.ts.map +1 -0
- package/lib/Error/SocialiteAuthError/SocialiteAuthError.js +17 -0
- package/lib/Global/helpers.d.ts.map +1 -1
- package/lib/Global/helpers.js +6 -4
- package/lib/Http/index.d.ts +3 -1
- package/lib/Http/index.d.ts.map +1 -1
- package/lib/Http/index.js +26 -5
- package/lib/Interface/index.d.ts +12 -3
- package/lib/Interface/index.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Builder.d.ts +12 -1
- package/lib/Jcc-eloquent/lib/Builder.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Builder.js +116 -4
- package/lib/Jcc-eloquent/lib/Interfaces/index.d.ts +37 -2
- package/lib/Jcc-eloquent/lib/Interfaces/index.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Migration.d.ts +6 -0
- package/lib/Jcc-eloquent/lib/Migration.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Migration.js +24 -2
- package/lib/Jcc-eloquent/lib/Model.d.ts +24 -7
- package/lib/Jcc-eloquent/lib/Model.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Model.js +35 -2
- package/lib/Jcc-eloquent/lib/QueryBuilder.d.ts +2 -1
- package/lib/Jcc-eloquent/lib/QueryBuilder.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/QueryBuilder.js +10 -1
- package/lib/Jcc-eloquent/lib/Rollback.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Rollback.js +9 -2
- package/lib/Jcc-eloquent/lib/Schema/BaseSchemaEntity/index.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Schema/BaseSchemaEntity/index.js +3 -3
- package/lib/Jcc-eloquent/lib/Schema/BluePrint/index.d.ts +6 -2
- package/lib/Jcc-eloquent/lib/Schema/BluePrint/index.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Schema/BluePrint/index.js +41 -12
- package/lib/Jcc-eloquent/lib/Schema/Translator/Sqlite.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Schema/Translator/Sqlite.js +21 -3
- package/lib/Jcc-eloquent/lib/Schema/Translator/postgres.d.ts +1 -0
- package/lib/Jcc-eloquent/lib/Schema/Translator/postgres.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Schema/Translator/postgres.js +70 -14
- package/lib/Jcc-eloquent/lib/Schema/index.d.ts +12 -0
- package/lib/Jcc-eloquent/lib/Schema/index.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/Schema/index.js +27 -6
- package/lib/Jcc-eloquent/lib/utils/index.d.ts +13 -0
- package/lib/Jcc-eloquent/lib/utils/index.d.ts.map +1 -1
- package/lib/Jcc-eloquent/lib/utils/index.js +62 -0
- package/lib/Middleware/index.d.ts.map +1 -1
- package/lib/Middleware/index.js +4 -7
- package/lib/Model/Sequelize.d.ts +3 -0
- package/lib/Model/Sequelize.d.ts.map +1 -0
- package/lib/Model/Sequelize.js +6 -0
- package/lib/Providers/SessionServiceProvider.d.ts +12 -0
- package/lib/Providers/SessionServiceProvider.d.ts.map +1 -0
- package/lib/Providers/SessionServiceProvider.js +47 -0
- package/lib/Queue/Controllers/QueueControllers.d.ts +4 -13
- package/lib/Queue/Controllers/QueueControllers.d.ts.map +1 -1
- package/lib/Queue/Controllers/QueueControllers.js +1 -16
- package/lib/Queue/Route/web.js +4 -1
- package/lib/Queue/index.d.ts +1 -0
- package/lib/Queue/index.d.ts.map +1 -1
- package/lib/Queue/index.js +3 -0
- package/lib/Queue/middleware/queueDashboardGuard.d.ts +7 -0
- package/lib/Queue/middleware/queueDashboardGuard.d.ts.map +1 -0
- package/lib/Queue/middleware/queueDashboardGuard.js +43 -0
- package/lib/Response/index.d.ts.map +1 -1
- package/lib/Response/index.js +6 -1
- package/lib/Routes/Route.d.ts +2 -2
- package/lib/Routes/Route.d.ts.map +1 -1
- package/lib/Routes/RouteBuilder.d.ts +2 -2
- package/lib/Routes/RouteBuilder.d.ts.map +1 -1
- package/lib/Security/CsrfMiddleware.d.ts.map +1 -1
- package/lib/Security/CsrfMiddleware.js +6 -4
- package/lib/Session/DatabaseSession.d.ts +9 -3
- package/lib/Session/DatabaseSession.d.ts.map +1 -1
- package/lib/Session/DatabaseSession.js +38 -36
- package/lib/Session/ExpressJccSession.d.ts +23 -0
- package/lib/Session/ExpressJccSession.d.ts.map +1 -0
- package/lib/Session/ExpressJccSession.js +110 -0
- package/lib/Session/RedisSession.d.ts +2 -2
- package/lib/Session/RedisSession.d.ts.map +1 -1
- package/lib/Session/RedisSession.js +19 -5
- package/lib/Session/SessionManager.d.ts +18 -4
- package/lib/Session/SessionManager.d.ts.map +1 -1
- package/lib/Session/SessionManager.js +53 -17
- package/lib/Socialite/AbstractProvider.d.ts +60 -0
- package/lib/Socialite/AbstractProvider.d.ts.map +1 -0
- package/lib/Socialite/AbstractProvider.js +136 -0
- package/lib/Socialite/Drivers/facebook/FacebookDriver.d.ts +9 -0
- package/lib/Socialite/Drivers/facebook/FacebookDriver.d.ts.map +1 -0
- package/lib/Socialite/Drivers/facebook/FacebookDriver.js +40 -0
- package/lib/Socialite/Drivers/facebook/FacebookProvider.d.ts +15 -0
- package/lib/Socialite/Drivers/facebook/FacebookProvider.d.ts.map +1 -0
- package/lib/Socialite/Drivers/facebook/FacebookProvider.js +28 -0
- package/lib/Socialite/Drivers/github/GitHubDriver.d.ts +9 -0
- package/lib/Socialite/Drivers/github/GitHubDriver.d.ts.map +1 -0
- package/lib/Socialite/Drivers/github/GitHubDriver.js +54 -0
- package/lib/Socialite/Drivers/github/GitHubProvider.d.ts +15 -0
- package/lib/Socialite/Drivers/github/GitHubProvider.d.ts.map +1 -0
- package/lib/Socialite/Drivers/github/GitHubProvider.js +28 -0
- package/lib/Socialite/Drivers/gitlab/GitLabDriver.d.ts +10 -0
- package/lib/Socialite/Drivers/gitlab/GitLabDriver.d.ts.map +1 -0
- package/lib/Socialite/Drivers/gitlab/GitLabDriver.js +37 -0
- package/lib/Socialite/Drivers/gitlab/GitLabProvider.d.ts +15 -0
- package/lib/Socialite/Drivers/gitlab/GitLabProvider.d.ts.map +1 -0
- package/lib/Socialite/Drivers/gitlab/GitLabProvider.js +28 -0
- package/lib/Socialite/Drivers/google/GoogleDriver.d.ts +9 -0
- package/lib/Socialite/Drivers/google/GoogleDriver.d.ts.map +1 -0
- package/lib/Socialite/Drivers/google/GoogleDriver.js +39 -0
- package/lib/Socialite/Drivers/google/GoogleProvider.d.ts +15 -0
- package/lib/Socialite/Drivers/google/GoogleProvider.d.ts.map +1 -0
- package/lib/Socialite/Drivers/google/GoogleProvider.js +28 -0
- package/lib/Socialite/Drivers/slack/SlackDriver.d.ts +9 -0
- package/lib/Socialite/Drivers/slack/SlackDriver.d.ts.map +1 -0
- package/lib/Socialite/Drivers/slack/SlackDriver.js +41 -0
- package/lib/Socialite/Drivers/slack/SlackProvider.d.ts +16 -0
- package/lib/Socialite/Drivers/slack/SlackProvider.d.ts.map +1 -0
- package/lib/Socialite/Drivers/slack/SlackProvider.js +37 -0
- package/lib/Socialite/Drivers/twitter/TwitterDriver.d.ts +9 -0
- package/lib/Socialite/Drivers/twitter/TwitterDriver.d.ts.map +1 -0
- package/lib/Socialite/Drivers/twitter/TwitterDriver.js +57 -0
- package/lib/Socialite/Drivers/twitter/TwitterProvider.d.ts +16 -0
- package/lib/Socialite/Drivers/twitter/TwitterProvider.d.ts.map +1 -0
- package/lib/Socialite/Drivers/twitter/TwitterProvider.js +38 -0
- package/lib/Socialite/SocialUser.d.ts +42 -0
- package/lib/Socialite/SocialUser.d.ts.map +1 -0
- package/lib/Socialite/SocialUser.js +116 -0
- package/lib/Socialite/Socialite.d.ts +13 -0
- package/lib/Socialite/Socialite.d.ts.map +1 -0
- package/lib/Socialite/Socialite.js +41 -0
- package/lib/Socialite/SocialiteProvider.d.ts +9 -0
- package/lib/Socialite/SocialiteProvider.d.ts.map +1 -0
- package/lib/Socialite/SocialiteProvider.js +15 -0
- package/lib/Socialite/config.d.ts +7 -0
- package/lib/Socialite/config.d.ts.map +1 -0
- package/lib/Socialite/config.js +44 -0
- package/lib/Socialite/constant.d.ts +18 -0
- package/lib/Socialite/constant.d.ts.map +1 -0
- package/lib/Socialite/constant.js +20 -0
- package/lib/Socialite/index.d.ts +13 -0
- package/lib/Socialite/index.d.ts.map +1 -0
- package/lib/Socialite/index.js +25 -0
- package/lib/Socialite/types.d.ts +13 -0
- package/lib/Socialite/types.d.ts.map +1 -0
- package/lib/Socialite/types.js +2 -0
- package/lib/Type/index.d.ts +1 -0
- package/lib/Type/index.d.ts.map +1 -1
- package/lib/Validation/Validator/CustomValidation.d.ts.map +1 -1
- package/lib/Validation/Validator/CustomValidation.js +2 -2
- package/lib/Validation/Validator/helper.d.ts.map +1 -1
- package/lib/Validation/Validator/helper.js +8 -1
- package/lib/util/index.d.ts +36 -1
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +123 -26
- package/package.json +1 -1
|
@@ -3,22 +3,27 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.authMiddleware = void 0;
|
|
4
4
|
const Config_1 = require("../Config/Config");
|
|
5
5
|
const util_1 = require("../util");
|
|
6
|
-
const { User } = (0, util_1.getModel)("User");
|
|
7
6
|
class AuthMiddleware {
|
|
8
7
|
/** Middleware: API authentication */
|
|
9
8
|
async apiAuth(req, res, next) {
|
|
9
|
+
const { User } = (0, util_1.getModel)("User");
|
|
10
10
|
const token = req.headers.authorization?.split(" ")[1] || req.cookies.auth_token;
|
|
11
11
|
if (!token)
|
|
12
12
|
return res.status(401).json({ message: "Not authorized" });
|
|
13
13
|
try {
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const payload = (0, util_1.jwtVerify)(token);
|
|
15
|
+
if (!(0, util_1.checkJwtAccessTokenPayload)(payload).ok) {
|
|
16
|
+
return res.status(401).json({ message: "Not authorized" });
|
|
17
|
+
}
|
|
18
|
+
const id = (0, util_1.jwtSubjectId)(payload);
|
|
19
|
+
const user = Config_1.config.get("DB_ORM") === "mongodb" ||
|
|
20
|
+
Config_1.config.get("DB_ORM") === "mongoose"
|
|
16
21
|
? await User.findById(id)
|
|
17
22
|
: await User.where("id", id).first();
|
|
18
23
|
if (!user)
|
|
19
24
|
return res.status(401).json({ message: "Not authorized" });
|
|
20
25
|
req.user = user;
|
|
21
|
-
req.id = id;
|
|
26
|
+
req.id = String(id);
|
|
22
27
|
next();
|
|
23
28
|
}
|
|
24
29
|
catch (err) {
|
|
@@ -26,15 +31,26 @@ class AuthMiddleware {
|
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
33
|
async auth(req, res, next) {
|
|
34
|
+
const { User } = (0, util_1.getModel)("User");
|
|
29
35
|
const token = req.cookies.auth_token;
|
|
30
|
-
if (!token)
|
|
36
|
+
if (!token) {
|
|
37
|
+
req.jccSession?.put("redirect", req.url || "/");
|
|
31
38
|
return res.redirect(`/login?redirect=${req.url || "/"}`);
|
|
39
|
+
}
|
|
32
40
|
try {
|
|
33
41
|
const payload = (0, util_1.jwtVerify)(token);
|
|
34
|
-
|
|
42
|
+
if (!(0, util_1.checkJwtAccessTokenPayload)(payload).ok) {
|
|
43
|
+
res.clearCookie("auth_token", (0, util_1.authSessionCookieOptions)());
|
|
44
|
+
res.clearCookie("refresh_token", (0, util_1.authSessionCookieOptions)());
|
|
45
|
+
req.jccSession?.put("redirect", req.url || "/");
|
|
46
|
+
return res.redirect(`/login?redirect=${req.url || "/"}`);
|
|
47
|
+
}
|
|
48
|
+
const id = (0, util_1.jwtSubjectId)(payload);
|
|
49
|
+
const user = await (0, util_1.findUserById)(User, id);
|
|
35
50
|
if (!user) {
|
|
36
|
-
res.clearCookie("auth_token");
|
|
37
|
-
res.clearCookie("refresh_token");
|
|
51
|
+
res.clearCookie("auth_token", (0, util_1.authSessionCookieOptions)());
|
|
52
|
+
res.clearCookie("refresh_token", (0, util_1.authSessionCookieOptions)());
|
|
53
|
+
req.jccSession?.put("redirect", req.url || "/");
|
|
38
54
|
return res.redirect(`/login?redirect=${req.url || "/"}`);
|
|
39
55
|
}
|
|
40
56
|
req.user = user;
|
|
@@ -42,8 +58,9 @@ class AuthMiddleware {
|
|
|
42
58
|
next();
|
|
43
59
|
}
|
|
44
60
|
catch (err) {
|
|
45
|
-
res.clearCookie("auth_token");
|
|
46
|
-
res.clearCookie("refresh_token");
|
|
61
|
+
res.clearCookie("auth_token", (0, util_1.authSessionCookieOptions)());
|
|
62
|
+
res.clearCookie("refresh_token", (0, util_1.authSessionCookieOptions)());
|
|
63
|
+
req.jccSession?.put("redirect", req.url || "/");
|
|
47
64
|
return res.redirect(`/login?redirect=${req.url || "/"}`);
|
|
48
65
|
}
|
|
49
66
|
}
|
|
@@ -55,8 +72,8 @@ class AuthMiddleware {
|
|
|
55
72
|
return res.redirect(303, req.previousUrls[1]);
|
|
56
73
|
}
|
|
57
74
|
else {
|
|
58
|
-
res.clearCookie("auth_token");
|
|
59
|
-
res.clearCookie("refresh_token");
|
|
75
|
+
res.clearCookie("auth_token", (0, util_1.authSessionCookieOptions)());
|
|
76
|
+
res.clearCookie("refresh_token", (0, util_1.authSessionCookieOptions)());
|
|
60
77
|
return res.redirect(303, req.url);
|
|
61
78
|
}
|
|
62
79
|
}
|
package/lib/Auth/index.d.ts
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
import { AppRequest, AppResponse, AppNext } from "../Interface";
|
|
2
|
+
import { type IRefreshTokenStore } from "./refreshTokenStore";
|
|
2
3
|
export declare class Authentication {
|
|
4
|
+
private static refreshStore;
|
|
5
|
+
/** Use a shared store (e.g. Redis) when running multiple app instances. */
|
|
6
|
+
static setRefreshTokenStore(store: IRefreshTokenStore): void;
|
|
3
7
|
/** Get user lookup field (email, phone, username) */
|
|
4
8
|
private static getCredentials;
|
|
5
9
|
/** Fetch user from DB (MongoDB, Sequelize, or JCC ORM) */
|
|
6
10
|
private static getUser;
|
|
7
|
-
/** Generate and attach tokens to cookies */
|
|
11
|
+
/** Generate and attach tokens to cookies (refresh is rotated server-side via `jti`). */
|
|
8
12
|
private static setTokens;
|
|
9
13
|
/** Handle user login attempt */
|
|
10
|
-
static attempt: (
|
|
14
|
+
static attempt: (next: AppNext, redirect?: string) => Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* After the user is resolved (e.g. OAuth via Socialite), issue JWT cookies
|
|
17
|
+
* and redirect or JSON response like {@link Authentication.attempt}.
|
|
18
|
+
*/
|
|
19
|
+
static completeLogin(req: AppRequest, res: AppResponse, userId: string | number, redirect?: string): Promise<void>;
|
|
11
20
|
/** Refresh token middleware */
|
|
12
21
|
static refreshToken(req: AppRequest, res: AppResponse, next: AppNext): Promise<AppResponse | undefined>;
|
|
13
22
|
/** Logout handler */
|
|
14
|
-
static logout(
|
|
23
|
+
static logout(): void;
|
|
24
|
+
/** True when the access cookie is a valid, usable JWT (not refresh / disallowed legacy). */
|
|
25
|
+
static check(): boolean;
|
|
26
|
+
static user(): Record<string, any>;
|
|
27
|
+
static id(): any;
|
|
28
|
+
static socialLogin(userId: string | number): Promise<void>;
|
|
15
29
|
}
|
|
16
30
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/Auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAgBhE,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,qBAAqB,CAAC;AAsB7B,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAC,YAAY,CAAgD;IAE3E,2EAA2E;IAC3E,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI;IAI5D,qDAAqD;IACrD,OAAO,CAAC,MAAM,CAAC,cAAc;IAc7B,0DAA0D;mBACrC,OAAO;IAqB5B,wFAAwF;IACxF,OAAO,CAAC,MAAM,CAAC,SAAS;IA0BxB,gCAAgC;IAChC,MAAM,CAAC,OAAO,GAAU,MAAM,OAAO,EAAE,WAAU,MAAgB,mBAqB/D;IAEF;;;OAGG;WACU,aAAa,CACxB,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,QAAQ,GAAE,MAAgB,GACzB,OAAO,CAAC,IAAI,CAAC;IA4BhB,+BAA+B;WAClB,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO;IAsC1E,qBAAqB;IACrB,MAAM,CAAC,MAAM;IAsBb,4FAA4F;IAC5F,MAAM,CAAC,KAAK,IAAI,OAAO;IAWvB,MAAM,CAAC,IAAI;IAIX,MAAM,CAAC,EAAE;WAII,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAGjD"}
|
package/lib/Auth/index.js
CHANGED
|
@@ -6,8 +6,28 @@ const util_1 = require("../util");
|
|
|
6
6
|
const Config_1 = require("../Config/Config");
|
|
7
7
|
const ValidationException_v2_1 = require("../Error/ValidationException-v2");
|
|
8
8
|
const Jcc_eloquent_1 = require("../Jcc-eloquent");
|
|
9
|
-
const
|
|
9
|
+
const refreshTokenStore_1 = require("./refreshTokenStore");
|
|
10
|
+
const REFRESH_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
11
|
+
const ACCESS_MAX_AGE_MS = 60 * 60 * 1000;
|
|
12
|
+
function clearAuthCookies(res) {
|
|
13
|
+
const base = (0, util_1.authSessionCookieOptions)();
|
|
14
|
+
res.clearCookie("auth_token", base);
|
|
15
|
+
res.clearCookie("refresh_token", base);
|
|
16
|
+
}
|
|
17
|
+
/** Avoid open redirects: only same-origin relative paths. */
|
|
18
|
+
function safeInternalRedirect(url, fallback) {
|
|
19
|
+
if (!url || typeof url !== "string")
|
|
20
|
+
return fallback;
|
|
21
|
+
const t = url.trim();
|
|
22
|
+
if (t.startsWith("/") && !t.startsWith("//") && !t.includes("\\"))
|
|
23
|
+
return t;
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
10
26
|
class Authentication {
|
|
27
|
+
/** Use a shared store (e.g. Redis) when running multiple app instances. */
|
|
28
|
+
static setRefreshTokenStore(store) {
|
|
29
|
+
_a.refreshStore = store;
|
|
30
|
+
}
|
|
11
31
|
/** Get user lookup field (email, phone, username) */
|
|
12
32
|
static getCredentials(data) {
|
|
13
33
|
const query = {};
|
|
@@ -24,12 +44,13 @@ class Authentication {
|
|
|
24
44
|
}
|
|
25
45
|
/** Fetch user from DB (MongoDB, Sequelize, or JCC ORM) */
|
|
26
46
|
static async getUser(data) {
|
|
47
|
+
const { User } = (0, util_1.getModel)("User");
|
|
27
48
|
const field = this.getCredentials(data);
|
|
28
49
|
if (!Object.keys(field).length)
|
|
29
50
|
return { user: null, field: "email" };
|
|
30
51
|
let user = null;
|
|
31
52
|
const orm = Config_1.config.get("DB_ORM");
|
|
32
|
-
if (orm === "mongodb") {
|
|
53
|
+
if (orm === "mongodb" || orm === "mongoose") {
|
|
33
54
|
user = await User.findOne(field).select("+password");
|
|
34
55
|
}
|
|
35
56
|
else if (orm === "sequelize") {
|
|
@@ -43,54 +64,140 @@ class Authentication {
|
|
|
43
64
|
}
|
|
44
65
|
return { user, field: Object.keys(field)[0] || "email" };
|
|
45
66
|
}
|
|
46
|
-
/** Generate and attach tokens to cookies */
|
|
67
|
+
/** Generate and attach tokens to cookies (refresh is rotated server-side via `jti`). */
|
|
47
68
|
static setTokens(res, userId) {
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
};
|
|
69
|
+
const id = String(userId);
|
|
70
|
+
const jti = _a.refreshStore.generateJti();
|
|
71
|
+
_a.refreshStore.register(jti, id, REFRESH_TTL_MS);
|
|
72
|
+
const accessToken = (0, util_1.jwtSign)(id, { expiresIn: "1h" });
|
|
73
|
+
const refreshToken = (0, util_1.jwtSign)({ id, typ: "refresh", jti }, { expiresIn: "7d" });
|
|
74
|
+
const cookieOptions = (0, util_1.authSessionCookieOptions)();
|
|
55
75
|
res.cookie("auth_token", accessToken, {
|
|
56
76
|
...cookieOptions,
|
|
57
|
-
maxAge:
|
|
77
|
+
maxAge: ACCESS_MAX_AGE_MS,
|
|
58
78
|
});
|
|
59
79
|
res.cookie("refresh_token", refreshToken, {
|
|
60
80
|
...cookieOptions,
|
|
61
|
-
maxAge:
|
|
81
|
+
maxAge: REFRESH_TTL_MS,
|
|
62
82
|
});
|
|
63
83
|
return { accessToken, refreshToken };
|
|
64
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* After the user is resolved (e.g. OAuth via Socialite), issue JWT cookies
|
|
87
|
+
* and redirect or JSON response like {@link Authentication.attempt}.
|
|
88
|
+
*/
|
|
89
|
+
static async completeLogin(req, res, userId, redirect = "/home") {
|
|
90
|
+
const { User } = (0, util_1.getModel)("User");
|
|
91
|
+
const tokens = this.setTokens(res, userId);
|
|
92
|
+
const user = await (0, util_1.findUserById)(User, userId);
|
|
93
|
+
if (!user) {
|
|
94
|
+
if (req.expectsJson() && !req.isInertia()) {
|
|
95
|
+
res.status(401).json({ message: "Unauthorized" });
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
req.jccSession?.flash("error", "Could not sign you in.");
|
|
99
|
+
res.redirect(303, "/login");
|
|
100
|
+
}
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (req.expectsJson() && !req.isInertia()) {
|
|
104
|
+
const plain = typeof user?.toObject === "function" ? user.toObject() : user;
|
|
105
|
+
res.status(200).json({
|
|
106
|
+
tokens: { accessToken: tokens.accessToken },
|
|
107
|
+
user: plain,
|
|
108
|
+
});
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const sessionRedirect = req.jccSession?.get("redirect") || "";
|
|
112
|
+
req.jccSession?.forget("redirect");
|
|
113
|
+
const redirectTo = safeInternalRedirect(sessionRedirect, redirect);
|
|
114
|
+
res.redirect(303, redirectTo);
|
|
115
|
+
}
|
|
65
116
|
/** Refresh token middleware */
|
|
66
117
|
static async refreshToken(req, res, next) {
|
|
118
|
+
const { User } = (0, util_1.getModel)("User");
|
|
67
119
|
try {
|
|
68
120
|
const refreshToken = req.cookies.refresh_token;
|
|
69
121
|
if (!refreshToken)
|
|
70
122
|
throw new Error("No refresh token");
|
|
71
|
-
const
|
|
123
|
+
const payload = (0, util_1.jwtVerify)(refreshToken);
|
|
124
|
+
const kind = (0, util_1.jwtTokenType)(payload);
|
|
125
|
+
if (kind === "access") {
|
|
126
|
+
throw new Error("Invalid refresh token");
|
|
127
|
+
}
|
|
128
|
+
const jti = payload != null &&
|
|
129
|
+
typeof payload === "object" &&
|
|
130
|
+
typeof payload.jti === "string"
|
|
131
|
+
? payload.jti
|
|
132
|
+
: "";
|
|
133
|
+
if (!jti) {
|
|
134
|
+
throw new Error("Invalid refresh token");
|
|
135
|
+
}
|
|
136
|
+
const session = _a.refreshStore.consume(jti);
|
|
137
|
+
const userId = (0, util_1.jwtSubjectId)(payload);
|
|
138
|
+
if (!session || session.userId !== String(userId)) {
|
|
139
|
+
throw new Error("Invalid refresh token");
|
|
140
|
+
}
|
|
72
141
|
this.setTokens(res, userId);
|
|
73
|
-
// Use universal finder
|
|
74
142
|
req.user = await (0, util_1.findUserById)(User, userId);
|
|
75
143
|
next();
|
|
76
144
|
}
|
|
77
145
|
catch (error) {
|
|
78
|
-
res
|
|
79
|
-
res.clearCookie("refresh_token");
|
|
146
|
+
clearAuthCookies(res);
|
|
80
147
|
return res.status(401).json({ message: "Unauthorized" });
|
|
81
148
|
}
|
|
82
149
|
}
|
|
83
150
|
/** Logout handler */
|
|
84
|
-
static logout(
|
|
85
|
-
|
|
86
|
-
res
|
|
151
|
+
static logout() {
|
|
152
|
+
const req = request();
|
|
153
|
+
const res = response();
|
|
154
|
+
try {
|
|
155
|
+
const rt = req.cookies?.refresh_token;
|
|
156
|
+
if (rt) {
|
|
157
|
+
const payload = (0, util_1.jwtVerify)(rt);
|
|
158
|
+
if (payload != null &&
|
|
159
|
+
typeof payload === "object" &&
|
|
160
|
+
typeof payload.jti === "string") {
|
|
161
|
+
_a.refreshStore.revoke(payload.jti);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
/* expired or malformed */
|
|
167
|
+
}
|
|
168
|
+
clearAuthCookies(res);
|
|
87
169
|
return res.redirect("/login");
|
|
88
170
|
}
|
|
171
|
+
/** True when the access cookie is a valid, usable JWT (not refresh / disallowed legacy). */
|
|
172
|
+
static check() {
|
|
173
|
+
const token = request().cookies?.auth_token;
|
|
174
|
+
if (!token)
|
|
175
|
+
return false;
|
|
176
|
+
try {
|
|
177
|
+
const payload = (0, util_1.jwtVerify)(token);
|
|
178
|
+
return (0, util_1.checkJwtAccessTokenPayload)(payload).ok;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
static user() {
|
|
185
|
+
return request().user;
|
|
186
|
+
}
|
|
187
|
+
static id() {
|
|
188
|
+
return request().user?.id || request().user?._id;
|
|
189
|
+
}
|
|
190
|
+
static async socialLogin(userId) {
|
|
191
|
+
return this.completeLogin(request(), response(), userId, "/home");
|
|
192
|
+
}
|
|
89
193
|
}
|
|
90
194
|
exports.Authentication = Authentication;
|
|
91
195
|
_a = Authentication;
|
|
196
|
+
Authentication.refreshStore = refreshTokenStore_1.defaultRefreshTokenStore;
|
|
92
197
|
/** Handle user login attempt */
|
|
93
|
-
Authentication.attempt = async (
|
|
198
|
+
Authentication.attempt = async (next, redirect = "/home") => {
|
|
199
|
+
const req = request();
|
|
200
|
+
const res = response();
|
|
94
201
|
try {
|
|
95
202
|
const { user, field } = await _a.getUser(req.body);
|
|
96
203
|
if (!user)
|
|
@@ -98,12 +205,7 @@ Authentication.attempt = async (req, res, next, redirect = "/home") => {
|
|
|
98
205
|
if (!(await (0, util_1.verifyHash)(req.body.password, user.password))) {
|
|
99
206
|
throw new ValidationException_v2_1.ValidationException({ [field]: ["Invalid credentials"] });
|
|
100
207
|
}
|
|
101
|
-
|
|
102
|
-
if (req.expectsJson() && !req.isInertia()) {
|
|
103
|
-
return res.status(200).json({ tokens, user });
|
|
104
|
-
}
|
|
105
|
-
const redirectTo = req.query.redirect?.toString() || redirect;
|
|
106
|
-
return res.redirect(303, redirectTo);
|
|
208
|
+
await _a.completeLogin(req, res, user.id || user._id, redirect);
|
|
107
209
|
}
|
|
108
210
|
catch (error) {
|
|
109
211
|
next(error);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RequestHandler } from "express";
|
|
2
|
+
/** Stricter limit for login attempts (per IP). */
|
|
3
|
+
export declare const loginRateLimit: RequestHandler;
|
|
4
|
+
/** Stricter limit for registration (per IP). */
|
|
5
|
+
export declare const registerRateLimit: RequestHandler;
|
|
6
|
+
//# sourceMappingURL=loginRateLimit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loginRateLimit.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Auth/loginRateLimit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,kDAAkD;AAClD,eAAO,MAAM,cAAc,EAAE,cAO3B,CAAC;AAEH,gDAAgD;AAChD,eAAO,MAAM,iBAAiB,EAAE,cAO9B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerRateLimit = exports.loginRateLimit = void 0;
|
|
7
|
+
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
8
|
+
/** Stricter limit for login attempts (per IP). */
|
|
9
|
+
exports.loginRateLimit = (0, express_rate_limit_1.default)({
|
|
10
|
+
windowMs: 15 * 60 * 1000,
|
|
11
|
+
max: 20,
|
|
12
|
+
message: { message: "Too many login attempts. Try again later." },
|
|
13
|
+
standardHeaders: true,
|
|
14
|
+
legacyHeaders: false,
|
|
15
|
+
validate: { trustProxy: false },
|
|
16
|
+
});
|
|
17
|
+
/** Stricter limit for registration (per IP). */
|
|
18
|
+
exports.registerRateLimit = (0, express_rate_limit_1.default)({
|
|
19
|
+
windowMs: 60 * 60 * 1000,
|
|
20
|
+
max: 10,
|
|
21
|
+
message: { message: "Too many registration attempts. Try again later." },
|
|
22
|
+
standardHeaders: true,
|
|
23
|
+
legacyHeaders: false,
|
|
24
|
+
validate: { trustProxy: false },
|
|
25
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type RefreshSession = {
|
|
2
|
+
userId: string;
|
|
3
|
+
expiresAt: number;
|
|
4
|
+
};
|
|
5
|
+
/** Pluggable store for refresh-token `jti` rotation (swap for Redis in multi-instance). */
|
|
6
|
+
export interface IRefreshTokenStore {
|
|
7
|
+
generateJti(): string;
|
|
8
|
+
register(jti: string, userId: string, ttlMs: number): void;
|
|
9
|
+
/** Remove and return the session if `jti` is valid and not expired. */
|
|
10
|
+
consume(jti: string): RefreshSession | undefined;
|
|
11
|
+
revoke(jti: string): void;
|
|
12
|
+
revokeAllForUser(userId: string): void;
|
|
13
|
+
}
|
|
14
|
+
export declare class MemoryRefreshTokenStore implements IRefreshTokenStore {
|
|
15
|
+
private readonly byJti;
|
|
16
|
+
generateJti(): string;
|
|
17
|
+
register(jti: string, userId: string, ttlMs: number): void;
|
|
18
|
+
consume(jti: string): RefreshSession | undefined;
|
|
19
|
+
revoke(jti: string): void;
|
|
20
|
+
revokeAllForUser(userId: string): void;
|
|
21
|
+
private prune;
|
|
22
|
+
}
|
|
23
|
+
export declare const defaultRefreshTokenStore: MemoryRefreshTokenStore;
|
|
24
|
+
//# sourceMappingURL=refreshTokenStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refreshTokenStore.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Auth/refreshTokenStore.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,WAAW,IAAI,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3D,uEAAuE;IACvE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC;AAED,qBAAa,uBAAwB,YAAW,kBAAkB;IAChE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAE3D,WAAW,IAAI,MAAM;IAIrB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ1D,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAQhD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAMtC,OAAO,CAAC,KAAK;CAMd;AAED,eAAO,MAAM,wBAAwB,yBAAgC,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultRefreshTokenStore = exports.MemoryRefreshTokenStore = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
class MemoryRefreshTokenStore {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.byJti = new Map();
|
|
8
|
+
}
|
|
9
|
+
generateJti() {
|
|
10
|
+
return (0, crypto_1.randomBytes)(32).toString("hex");
|
|
11
|
+
}
|
|
12
|
+
register(jti, userId, ttlMs) {
|
|
13
|
+
this.prune();
|
|
14
|
+
this.byJti.set(jti, {
|
|
15
|
+
userId,
|
|
16
|
+
expiresAt: Date.now() + ttlMs,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
consume(jti) {
|
|
20
|
+
const row = this.byJti.get(jti);
|
|
21
|
+
if (!row)
|
|
22
|
+
return undefined;
|
|
23
|
+
this.byJti.delete(jti);
|
|
24
|
+
if (Date.now() > row.expiresAt)
|
|
25
|
+
return undefined;
|
|
26
|
+
return row;
|
|
27
|
+
}
|
|
28
|
+
revoke(jti) {
|
|
29
|
+
this.byJti.delete(jti);
|
|
30
|
+
}
|
|
31
|
+
revokeAllForUser(userId) {
|
|
32
|
+
for (const [k, v] of this.byJti) {
|
|
33
|
+
if (v.userId === userId)
|
|
34
|
+
this.byJti.delete(k);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
prune() {
|
|
38
|
+
const now = Date.now();
|
|
39
|
+
for (const [k, v] of this.byJti) {
|
|
40
|
+
if (v.expiresAt < now)
|
|
41
|
+
this.byJti.delete(k);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.MemoryRefreshTokenStore = MemoryRefreshTokenStore;
|
|
46
|
+
exports.defaultRefreshTokenStore = new MemoryRefreshTokenStore();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DBCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/DBCommand.ts"],"names":[],"mappings":"AAMA,qBAAa,SAAS;IACpB,OAAO,CAAC,WAAW,CAA0C;IAE7D,OAAO,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"DBCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/DBCommand.ts"],"names":[],"mappings":"AAMA,qBAAa,SAAS;IACpB,OAAO,CAAC,WAAW,CAA0C;IAE7D,OAAO,CAAC,YAAY;IAad,IAAI;IAqBJ,YAAY,CAAC,UAAU,EAAE,MAAM;IAW/B,IAAI;CA+BX"}
|
|
@@ -14,11 +14,17 @@ class DBCommand {
|
|
|
14
14
|
this.seedersPath = `${rootPath}/database/seeders`;
|
|
15
15
|
}
|
|
16
16
|
getSeederDir(seederFile) {
|
|
17
|
+
const base = `${this.seedersPath}/${seederFile}`;
|
|
17
18
|
try {
|
|
18
|
-
return require(
|
|
19
|
+
return require(base);
|
|
19
20
|
}
|
|
20
|
-
catch
|
|
21
|
-
|
|
21
|
+
catch {
|
|
22
|
+
try {
|
|
23
|
+
return require(`${base}.ts`);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
console.log(`Can't get the seeder with name of ${seederFile}`);
|
|
27
|
+
}
|
|
22
28
|
}
|
|
23
29
|
}
|
|
24
30
|
async seed() {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a cryptographically strong secret (64 hex chars = 32 bytes).
|
|
3
|
+
* Default env key: JWT_SECRET (meets production length checks in this framework).
|
|
4
|
+
*/
|
|
5
|
+
export declare function runKeyGenerate(firstArg?: string, secondArg?: string): void;
|
|
6
|
+
//# sourceMappingURL=KeyGenerateCommand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KeyGenerateCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/KeyGenerateCommand.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAK,EAAE,SAAS,SAAK,GAAG,IAAI,CAoClE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runKeyGenerate = runKeyGenerate;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const app_root_path_1 = __importDefault(require("app-root-path"));
|
|
11
|
+
const colors_1 = __importDefault(require("colors"));
|
|
12
|
+
function escapeRegex(s) {
|
|
13
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate a cryptographically strong secret (64 hex chars = 32 bytes).
|
|
17
|
+
* Default env key: JWT_SECRET (meets production length checks in this framework).
|
|
18
|
+
*/
|
|
19
|
+
function runKeyGenerate(firstArg = "", secondArg = "") {
|
|
20
|
+
const showOnly = firstArg === "show" ||
|
|
21
|
+
secondArg === "show" ||
|
|
22
|
+
secondArg === "--show";
|
|
23
|
+
const keyName = firstArg && firstArg !== "show" ? firstArg : "JWT_SECRET";
|
|
24
|
+
const value = (0, crypto_1.randomBytes)(32).toString("hex");
|
|
25
|
+
if (showOnly) {
|
|
26
|
+
console.log(colors_1.default.green(`${keyName}=`) + value);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const envPath = path_1.default.join(app_root_path_1.default.path, ".env");
|
|
30
|
+
if (!fs_1.default.existsSync(envPath)) {
|
|
31
|
+
console.log(colors_1.default.yellow(".env not found. Add this line to your environment file:\n"));
|
|
32
|
+
console.log(colors_1.default.cyan(`${keyName}=${value}\n`));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let contents = fs_1.default.readFileSync(envPath, "utf8");
|
|
36
|
+
const re = new RegExp(`^${escapeRegex(keyName)}=.*$`, "m");
|
|
37
|
+
const line = `${keyName}=${value}`;
|
|
38
|
+
if (re.test(contents)) {
|
|
39
|
+
contents = contents.replace(re, line);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
contents = contents.replace(/\s*$/, "") + "\n" + line + "\n";
|
|
43
|
+
}
|
|
44
|
+
fs_1.default.writeFileSync(envPath, contents, "utf8");
|
|
45
|
+
console.log(colors_1.default.green(`✓ Set ${keyName} in .env`) +
|
|
46
|
+
colors_1.default.gray(` (${value.length} characters)`));
|
|
47
|
+
}
|
|
@@ -9,12 +9,14 @@ export declare class ConsoleKernel {
|
|
|
9
9
|
private _make;
|
|
10
10
|
private _route;
|
|
11
11
|
private _schedule;
|
|
12
|
+
private _watch;
|
|
12
13
|
private _app;
|
|
13
14
|
private get migrate();
|
|
14
15
|
private get db();
|
|
15
16
|
private get make();
|
|
16
17
|
private get route();
|
|
17
18
|
private get schedule();
|
|
19
|
+
private get watch();
|
|
18
20
|
private app;
|
|
19
21
|
constructor();
|
|
20
22
|
/** Load user commands from app/Console/Command (guarded, non-blocking for missing dir) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeArtisanCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/NodeArtisanCommand.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"NodeArtisanCommand.d.ts","sourceRoot":"","sources":["../../../jcc-express-mvc/lib/Command-Line/NodeArtisanCommand.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAK1B;IACF,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,IAAI,CAAc;IAE1B,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,EAAE,GAEb;IAED,OAAO,KAAK,IAAI,GAEf;IAED,OAAO,KAAK,KAAK,GAEhB;IAED,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,KAAK,GAEhB;IACD,OAAO,CAAC,GAAG;;IAWX,0FAA0F;IAC1F,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,aAAa;IAOrB,wFAAwF;IACxF,OAAO,CAAC,SAAS;IAkBjB,OAAO,CAAC,aAAa;IAoLrB,OAAO,CAAC,QAAQ;IA+HhB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;CA4BpD"}
|
|
@@ -18,7 +18,9 @@ const MakeCommand_1 = require("./MakeCommand");
|
|
|
18
18
|
const RouteCommand_1 = require("./RouteCommand");
|
|
19
19
|
const ScheduleCommand_1 = require("./ScheduleCommand");
|
|
20
20
|
const InertiaCommand_1 = require("./InertiaCommand");
|
|
21
|
+
const KeyGenerateCommand_1 = require("./KeyGenerateCommand");
|
|
21
22
|
const Tinker_1 = require("./NodeTinker/Tinker");
|
|
23
|
+
const WatchCommand_1 = require("./WatchCommand");
|
|
22
24
|
const util_1 = require("../util");
|
|
23
25
|
/** Parse key=value from secondArg (e.g. steps=2, class=UserSeeder) */
|
|
24
26
|
const parseOption = (secondArg, key) => {
|
|
@@ -43,6 +45,9 @@ class ConsoleKernel {
|
|
|
43
45
|
get schedule() {
|
|
44
46
|
return (this._schedule ??= new ScheduleCommand_1.ScheduleCommand());
|
|
45
47
|
}
|
|
48
|
+
get watch() {
|
|
49
|
+
return (this._watch ??= new WatchCommand_1.WatchCommand());
|
|
50
|
+
}
|
|
46
51
|
app() {
|
|
47
52
|
const bootstrap = require(`${app_root_path_1.default.path}/bootstrap/app`);
|
|
48
53
|
const app = bootstrap.app;
|
|
@@ -57,6 +62,7 @@ class ConsoleKernel {
|
|
|
57
62
|
this._make = null;
|
|
58
63
|
this._route = null;
|
|
59
64
|
this._schedule = null;
|
|
65
|
+
this._watch = null;
|
|
60
66
|
this._app = this.app();
|
|
61
67
|
this.loadCustomCommands();
|
|
62
68
|
}
|
|
@@ -184,13 +190,22 @@ class ConsoleKernel {
|
|
|
184
190
|
: undefined;
|
|
185
191
|
return this.route.display(mw);
|
|
186
192
|
}));
|
|
187
|
-
this.defineCommand("tinker").action(this.runAction(() => Tinker_1.
|
|
188
|
-
this.defineCommand("inertia:start-ssr").action(this.runAction(() => InertiaCommand_1.InertiaCommand.startInertiaSSR()));
|
|
193
|
+
this.defineCommand("tinker").action(this.runAction(() => (0, Tinker_1.getTinker)().start(), { exit: false }));
|
|
194
|
+
this.defineCommand("inertia:start-ssr").action(this.runAction(() => InertiaCommand_1.InertiaCommand.startInertiaSSR(), { exit: false }));
|
|
195
|
+
this.defineCommand("serve")
|
|
196
|
+
.alias("watch")
|
|
197
|
+
.action(this.runAction((firstArg) => this.watch.run(firstArg || "server.ts"), {
|
|
198
|
+
exit: false,
|
|
199
|
+
}));
|
|
189
200
|
// ─── schedule (was missing) ─────────────────────────────────────────
|
|
190
201
|
this.defineCommand("schedule:run").action(this.runAction(() => this.schedule.run(), { exit: false }));
|
|
191
202
|
this.defineCommand("schedule:list").action(this.runAction(() => this.schedule.list()));
|
|
192
203
|
// ─── build ──────────────────────────────────────────────────────────
|
|
193
204
|
this.defineCommand("build").action(this.runAction(() => (0, buildCommand_1.BuildCommand)()));
|
|
205
|
+
// ─── key (JWT / app secrets) ─────────────────────────────────────────
|
|
206
|
+
this.defineCommand("key:generate")
|
|
207
|
+
.description("Generate a random secret (default: JWT_SECRET in .env). Use 'show' to print only.")
|
|
208
|
+
.action(this.runAction((firstArg, secondArg) => (0, KeyGenerateCommand_1.runKeyGenerate)(firstArg ?? "", secondArg ?? "")));
|
|
194
209
|
// ─── custom user commands ────────────────────────────────────────────
|
|
195
210
|
for (const { signature, description, CommandClass } of this
|
|
196
211
|
.customCommands) {
|
|
@@ -235,7 +250,9 @@ class ConsoleKernel {
|
|
|
235
250
|
console.log(line("route:list [middleware=]", "Display routes (optionally filtered)\n"));
|
|
236
251
|
console.log(section("⚡ Development Tools:"));
|
|
237
252
|
console.log(line("tinker", "Start the interactive Tinker REPL"));
|
|
238
|
-
console.log(line("
|
|
253
|
+
console.log(line("serve [entry]", "Watch files and restart app on changes"));
|
|
254
|
+
console.log(line("build", "Build the application for production"));
|
|
255
|
+
console.log(line("key:generate [name] [show]", "Random secret → .env (default JWT_SECRET); name=env key, show=print only") + "\n");
|
|
239
256
|
console.log(section("⏰ Schedule Commands:"));
|
|
240
257
|
console.log(line("schedule:run", "Run scheduled tasks (runs continuously)"));
|
|
241
258
|
console.log(line("schedule:list", "List all scheduled tasks\n"));
|
|
@@ -126,6 +126,9 @@ export declare class Tinker {
|
|
|
126
126
|
*/
|
|
127
127
|
private exit;
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Lazily construct Tinker so importing the artisan kernel does not attach
|
|
131
|
+
* readline to stdin/stdout (which felt like Tinker “running” for every command).
|
|
132
|
+
*/
|
|
133
|
+
export declare function getTinker(config?: TinkerConfig): Tinker;
|
|
131
134
|
//# sourceMappingURL=Tinker.d.ts.map
|