prostgles-server 2.0.178 → 2.0.179
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/AuthHandler.d.ts +4 -4
- package/dist/AuthHandler.d.ts.map +1 -1
- package/dist/DBSchemaBuilder.d.ts +6 -6
- package/dist/DBSchemaBuilder.d.ts.map +1 -1
- package/dist/DBSchemaBuilder.js +25 -8
- package/dist/DBSchemaBuilder.js.map +1 -1
- package/dist/DboBuilder.d.ts +20 -21
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +1 -1
- package/dist/DboBuilder.js.map +1 -1
- package/dist/Prostgles.d.ts +8 -10
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js.map +1 -1
- package/dist/PublishParser.d.ts +37 -37
- package/dist/PublishParser.d.ts.map +1 -1
- package/dist/PublishParser.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/lib/AuthHandler.d.ts +148 -0
- package/lib/AuthHandler.d.ts.map +1 -0
- package/lib/AuthHandler.js +411 -0
- package/lib/AuthHandler.ts +3 -3
- package/lib/DBEventsManager.d.ts +38 -0
- package/lib/DBEventsManager.d.ts.map +1 -0
- package/lib/DBEventsManager.js +136 -0
- package/lib/DBSchemaBuilder.d.ts +11 -0
- package/lib/DBSchemaBuilder.d.ts.map +1 -0
- package/lib/DBSchemaBuilder.js +102 -0
- package/lib/DBSchemaBuilder.ts +62 -27
- package/lib/DboBuilder.d.ts +428 -0
- package/lib/DboBuilder.d.ts.map +1 -0
- package/lib/DboBuilder.js +3078 -0
- package/lib/DboBuilder.ts +25 -25
- package/lib/FileManager.d.ts +168 -0
- package/lib/FileManager.d.ts.map +1 -0
- package/lib/FileManager.js +474 -0
- package/lib/Filtering.d.ts +15 -0
- package/lib/Filtering.d.ts.map +1 -0
- package/lib/Filtering.js +299 -0
- package/lib/PostgresNotifListenManager.d.ts +27 -0
- package/lib/PostgresNotifListenManager.d.ts.map +1 -0
- package/lib/PostgresNotifListenManager.js +122 -0
- package/lib/Prostgles.d.ts +193 -0
- package/lib/Prostgles.d.ts.map +1 -0
- package/lib/Prostgles.js +579 -0
- package/lib/Prostgles.ts +6 -6
- package/lib/PubSubManager.d.ts +157 -0
- package/lib/PubSubManager.d.ts.map +1 -0
- package/lib/PubSubManager.js +1400 -0
- package/lib/PublishParser.d.ts +262 -0
- package/lib/PublishParser.d.ts.map +1 -0
- package/lib/PublishParser.js +390 -0
- package/lib/PublishParser.ts +39 -38
- package/lib/QueryBuilder.d.ts +124 -0
- package/lib/QueryBuilder.d.ts.map +1 -0
- package/lib/QueryBuilder.js +1349 -0
- package/lib/SyncReplication.d.ts +34 -0
- package/lib/SyncReplication.d.ts.map +1 -0
- package/lib/SyncReplication.js +411 -0
- package/lib/TableConfig.d.ts +175 -0
- package/lib/TableConfig.d.ts.map +1 -0
- package/lib/TableConfig.js +231 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +45 -0
- package/lib/index.ts +3 -4
- package/lib/shortestPath.d.ts +10 -0
- package/lib/shortestPath.d.ts.map +1 -0
- package/lib/shortestPath.js +111 -0
- package/lib/utils.d.ts +2 -0
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +5 -0
- package/package.json +3 -3
- package/tests/client/PID.txt +1 -1
- package/tests/client/index.d.ts +1 -1
- package/tests/client/index.d.ts.map +1 -1
- package/tests/client_only_queries.d.ts +4 -0
- package/tests/client_only_queries.d.ts.map +1 -0
- package/tests/isomorphic_queries.d.ts +6 -0
- package/tests/isomorphic_queries.d.ts.map +1 -0
- package/tests/server/DBoGenerated.d.ts +97 -193
- package/tests/server/dboTypeCheck.d.ts +2 -0
- package/tests/server/dboTypeCheck.d.ts.map +1 -0
- package/tests/server/dboTypeCheck.js +14 -0
- package/tests/server/dboTypeCheck.ts +17 -0
- package/tests/server/index.d.ts +2 -0
- package/tests/server/index.d.ts.map +1 -0
- package/tests/server/index.js +11 -11
- package/tests/server/index.ts +23 -16
- package/tests/server/package-lock.json +5 -5
- package/tests/server/publishTypeCheck.d.ts +2 -0
- package/tests/server/publishTypeCheck.d.ts.map +1 -0
- package/tests/server/publishTypeCheck.js +120 -0
- package/tests/server/publishTypeCheck.ts +129 -0
- package/tests/server/tsconfig.json +4 -5
- package/tests/server_only_queries.d.ts +2 -0
- package/tests/server_only_queries.d.ts.map +1 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { AnyObject } from "prostgles-types";
|
|
2
|
+
import { LocalParams, PRGLIOSocket } from "./DboBuilder";
|
|
3
|
+
import { DBOFullyTyped } from "./DBSchemaBuilder";
|
|
4
|
+
import { DB, DBHandlerServer, Prostgles } from "./Prostgles";
|
|
5
|
+
declare type Awaitable<T> = T | Promise<T>;
|
|
6
|
+
declare type AuthSocketSchema = {
|
|
7
|
+
user?: AnyObject;
|
|
8
|
+
register?: boolean;
|
|
9
|
+
login?: boolean;
|
|
10
|
+
logout?: boolean;
|
|
11
|
+
pathGuard?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare type ExpressReq = {
|
|
14
|
+
body?: AnyObject;
|
|
15
|
+
query?: AnyObject;
|
|
16
|
+
cookies?: AnyObject;
|
|
17
|
+
params?: AnyObject;
|
|
18
|
+
path: string;
|
|
19
|
+
originalUrl: string;
|
|
20
|
+
};
|
|
21
|
+
declare type ExpressRes = {
|
|
22
|
+
status: (code: number) => ({
|
|
23
|
+
json: (response: AnyObject) => any;
|
|
24
|
+
});
|
|
25
|
+
cookie: (name: string, value: string, options: AnyObject) => any;
|
|
26
|
+
sendFile: (filepath: string) => void;
|
|
27
|
+
redirect: (url: string) => void;
|
|
28
|
+
};
|
|
29
|
+
export declare type BasicSession = {
|
|
30
|
+
/** Must be hard to bruteforce */
|
|
31
|
+
sid: string;
|
|
32
|
+
/** UNIX millisecond timestamp */
|
|
33
|
+
expires: number;
|
|
34
|
+
};
|
|
35
|
+
export declare type AuthClientRequest = {
|
|
36
|
+
socket: any;
|
|
37
|
+
} | {
|
|
38
|
+
httpReq: ExpressReq;
|
|
39
|
+
};
|
|
40
|
+
export declare type Auth<S = void> = {
|
|
41
|
+
/**
|
|
42
|
+
* Name of the cookie or socket hadnshake query param that represents the session id.
|
|
43
|
+
* Defaults to "session_id"
|
|
44
|
+
*/
|
|
45
|
+
sidKeyName?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Response time rounding in milliseconds to prevent timing attacks on login. Login response time should always be a multiple of this value. Defaults to 500 milliseconds
|
|
48
|
+
*/
|
|
49
|
+
responseThrottle?: number;
|
|
50
|
+
expressConfig?: {
|
|
51
|
+
/**
|
|
52
|
+
* Express app instance. If provided Prostgles will attempt to set sidKeyName to user cookie
|
|
53
|
+
*/
|
|
54
|
+
app: any;
|
|
55
|
+
/**
|
|
56
|
+
* Used in allowing logging in through express. Defaults to /login
|
|
57
|
+
*/
|
|
58
|
+
loginRoute?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Used in allowing logging out through express. Defaults to /logout
|
|
61
|
+
*/
|
|
62
|
+
logoutGetPath?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Options used in setting the cookie after a successful login
|
|
65
|
+
*/
|
|
66
|
+
cookieOptions?: AnyObject;
|
|
67
|
+
/**
|
|
68
|
+
* If provided, any client requests to NOT these routes (or their subroutes) will be redirected to loginRoute and then redirected back to the initial route after logging in
|
|
69
|
+
*/
|
|
70
|
+
publicRoutes?: string[];
|
|
71
|
+
/**
|
|
72
|
+
* False by default. If false and userRoutes are provided then the socket will request window.location.reload if the current url is on a user route.
|
|
73
|
+
*/
|
|
74
|
+
disableSocketAuthGuard?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Will be called after a GET request is authorised
|
|
77
|
+
*/
|
|
78
|
+
onGetRequestOK?: (req: ExpressReq, res: ExpressRes) => any;
|
|
79
|
+
/**
|
|
80
|
+
* Name of get url parameter used in redirecting user after successful login. Defaults to returnURL
|
|
81
|
+
*/
|
|
82
|
+
returnURL?: string;
|
|
83
|
+
magicLinks?: {
|
|
84
|
+
/**
|
|
85
|
+
* Will default to /magic-link
|
|
86
|
+
*/
|
|
87
|
+
route?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Used in creating a session/logging in using a magic link
|
|
90
|
+
*/
|
|
91
|
+
check: (magicId: string, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<BasicSession | undefined>;
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
getUser: (sid: string | undefined, dbo: DBOFullyTyped<S>, db: DB, client: AuthClientRequest) => Awaitable<{
|
|
95
|
+
/**
|
|
96
|
+
* User data used on server. Mainly used in http request auth
|
|
97
|
+
*/
|
|
98
|
+
user: AnyObject;
|
|
99
|
+
/**
|
|
100
|
+
* User data sent to client. Mainly used in socket request auth
|
|
101
|
+
*/
|
|
102
|
+
clientUser: AnyObject;
|
|
103
|
+
} | undefined>;
|
|
104
|
+
register?: (params: AnyObject, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<BasicSession> | BasicSession;
|
|
105
|
+
login?: (params: AnyObject, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<BasicSession> | BasicSession;
|
|
106
|
+
logout?: (sid: string | undefined, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<any>;
|
|
107
|
+
/**
|
|
108
|
+
* If provided then then session info will be saved on socket.__prglCache and reused from there
|
|
109
|
+
*/
|
|
110
|
+
cacheSession?: {
|
|
111
|
+
getSession: (sid: string | undefined, dbo: DBOFullyTyped<S>, db: DB) => Awaitable<BasicSession>;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
export declare type ClientInfo = {
|
|
115
|
+
user?: AnyObject;
|
|
116
|
+
clientUser?: AnyObject;
|
|
117
|
+
sid?: string;
|
|
118
|
+
};
|
|
119
|
+
export default class AuthHandler {
|
|
120
|
+
protected opts?: Auth;
|
|
121
|
+
dbo: DBHandlerServer;
|
|
122
|
+
db: DB;
|
|
123
|
+
sidKeyName?: string;
|
|
124
|
+
returnURL?: string;
|
|
125
|
+
loginRoute?: string;
|
|
126
|
+
logoutGetPath?: string;
|
|
127
|
+
constructor(prostgles: Prostgles);
|
|
128
|
+
validateSid: (sid: string | undefined) => string;
|
|
129
|
+
matchesRoute: (route: string | undefined, clientFullRoute: string) => boolean;
|
|
130
|
+
isUserRoute: (pathname: string) => boolean;
|
|
131
|
+
private setCookieAndGoToReturnURLIFSet;
|
|
132
|
+
getUser: (clientReq: AuthClientRequest) => Promise<AnyObject | undefined>;
|
|
133
|
+
init(): Promise<void>;
|
|
134
|
+
throttledFunc: <T>(func: () => Promise<T>, throttle?: number) => Promise<T>;
|
|
135
|
+
loginThrottled: (params: AnyObject) => Promise<BasicSession>;
|
|
136
|
+
/**
|
|
137
|
+
* Will return first sid value found in : http cookie or query params
|
|
138
|
+
* Based on sid names in auth
|
|
139
|
+
* @param localParams
|
|
140
|
+
* @returns string
|
|
141
|
+
*/
|
|
142
|
+
getSID(localParams: LocalParams): string | undefined;
|
|
143
|
+
getClientInfo(localParams: Pick<LocalParams, "socket" | "httpReq">): Promise<ClientInfo | undefined>;
|
|
144
|
+
isValidSocketSession: (socket: PRGLIOSocket, session: BasicSession) => boolean;
|
|
145
|
+
makeSocketAuth: (socket: PRGLIOSocket) => Promise<AuthSocketSchema>;
|
|
146
|
+
}
|
|
147
|
+
export {};
|
|
148
|
+
//# sourceMappingURL=AuthHandler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthHandler.d.ts","sourceRoot":"","sources":["AuthHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const prostgles_types_1 = require("prostgles-types");
|
|
4
|
+
class AuthHandler {
|
|
5
|
+
constructor(prostgles) {
|
|
6
|
+
this.validateSid = (sid) => {
|
|
7
|
+
if (!sid)
|
|
8
|
+
return undefined;
|
|
9
|
+
if (typeof sid !== "string")
|
|
10
|
+
throw "sid missing or not a string";
|
|
11
|
+
return sid;
|
|
12
|
+
};
|
|
13
|
+
this.matchesRoute = (route, clientFullRoute) => {
|
|
14
|
+
return route && clientFullRoute && (route === clientFullRoute ||
|
|
15
|
+
clientFullRoute.startsWith(route) && ["/", "?", "#"].includes(clientFullRoute.slice(-1)));
|
|
16
|
+
};
|
|
17
|
+
this.isUserRoute = (pathname) => {
|
|
18
|
+
const pubRoutes = [
|
|
19
|
+
...this.opts?.expressConfig?.publicRoutes || [],
|
|
20
|
+
];
|
|
21
|
+
if (this.loginRoute)
|
|
22
|
+
pubRoutes.push(this.loginRoute);
|
|
23
|
+
if (this.logoutGetPath)
|
|
24
|
+
pubRoutes.push(this.logoutGetPath);
|
|
25
|
+
return Boolean(!pubRoutes.find(publicRoute => {
|
|
26
|
+
return this.matchesRoute(publicRoute, pathname); // publicRoute === pathname || pathname.startsWith(publicRoute) && ["/", "?", "#"].includes(pathname.slice(-1));
|
|
27
|
+
}));
|
|
28
|
+
};
|
|
29
|
+
this.setCookieAndGoToReturnURLIFSet = (cookie, r) => {
|
|
30
|
+
const { sid, expires } = cookie;
|
|
31
|
+
const { res, req } = r;
|
|
32
|
+
if (sid) {
|
|
33
|
+
let maxAge = 1000 * 60 * 60 * 24; // 24 hours
|
|
34
|
+
if (expires && Number.isFinite(expires) && !isNaN(+new Date(expires))) {
|
|
35
|
+
maxAge = (+new Date(expires) - Date.now());
|
|
36
|
+
}
|
|
37
|
+
let options = {
|
|
38
|
+
maxAge,
|
|
39
|
+
httpOnly: true, // The cookie only accessible by the web server
|
|
40
|
+
//signed: true // Indicates if the cookie should be signed
|
|
41
|
+
};
|
|
42
|
+
const cookieOpts = { ...options, secure: true, sameSite: "strict", ...(this.opts?.expressConfig?.cookieOptions || {}) };
|
|
43
|
+
const cookieData = sid;
|
|
44
|
+
if (!this.sidKeyName || !this.returnURL)
|
|
45
|
+
throw "sidKeyName or returnURL missing";
|
|
46
|
+
res.cookie(this.sidKeyName, cookieData, cookieOpts);
|
|
47
|
+
const successURL = getReturnUrl(req, this.returnURL) || "/";
|
|
48
|
+
res.redirect(successURL);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw ("no user or session");
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
this.getUser = async (clientReq) => {
|
|
55
|
+
if (!this.sidKeyName || !this.opts?.getUser)
|
|
56
|
+
throw "sidKeyName or this.opts.getUser missing";
|
|
57
|
+
const sid = "httpReq" in clientReq ? clientReq.httpReq?.cookies?.[this.sidKeyName] : clientReq.socket;
|
|
58
|
+
if (!sid)
|
|
59
|
+
return undefined;
|
|
60
|
+
try {
|
|
61
|
+
return this.throttledFunc(async () => {
|
|
62
|
+
return this.opts.getUser(this.validateSid(sid), this.dbo, this.db, clientReq);
|
|
63
|
+
}, 50);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
console.error(err);
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
};
|
|
70
|
+
this.throttledFunc = (func, throttle = 500) => {
|
|
71
|
+
return new Promise(async (resolve, reject) => {
|
|
72
|
+
let interval, result, error, finished = false;
|
|
73
|
+
/**
|
|
74
|
+
* Throttle response times to prevent timing attacks
|
|
75
|
+
*/
|
|
76
|
+
interval = setInterval(() => {
|
|
77
|
+
if (finished) {
|
|
78
|
+
clearInterval(interval);
|
|
79
|
+
if (error) {
|
|
80
|
+
reject(error);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
resolve(result);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}, throttle);
|
|
87
|
+
try {
|
|
88
|
+
result = await func();
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
console.log(err);
|
|
92
|
+
error = err;
|
|
93
|
+
}
|
|
94
|
+
finished = true;
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
this.loginThrottled = async (params) => {
|
|
98
|
+
if (!this.opts?.login)
|
|
99
|
+
throw "Auth login config missing";
|
|
100
|
+
const { responseThrottle = 500 } = this.opts;
|
|
101
|
+
return this.throttledFunc(async () => {
|
|
102
|
+
let result = await this.opts?.login?.(params, this.dbo, this.db);
|
|
103
|
+
const err = {
|
|
104
|
+
msg: "Bad login result type. \nExpecting: undefined | null | { sid: string; expires: number } but got: " + JSON.stringify(result)
|
|
105
|
+
};
|
|
106
|
+
if (!result)
|
|
107
|
+
throw err;
|
|
108
|
+
if (result && (typeof result.sid !== "string" || typeof result.expires !== "number") || !result && ![undefined, null].includes(result)) {
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
if (result && result.expires < Date.now()) {
|
|
112
|
+
throw { msg: "auth.login() is returning an expired session. Can only login with a session.expires greater than Date.now()" };
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}, responseThrottle);
|
|
116
|
+
};
|
|
117
|
+
this.isValidSocketSession = (socket, session) => {
|
|
118
|
+
const hasExpired = Boolean(session && session.expires <= Date.now());
|
|
119
|
+
if (this.opts?.expressConfig?.publicRoutes && !this.opts.expressConfig?.disableSocketAuthGuard) {
|
|
120
|
+
if (hasExpired) {
|
|
121
|
+
socket.emit(prostgles_types_1.CHANNELS.AUTHGUARD, { shouldReload: true });
|
|
122
|
+
throw "";
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return Boolean(session && !hasExpired);
|
|
126
|
+
};
|
|
127
|
+
this.makeSocketAuth = async (socket) => {
|
|
128
|
+
if (!this.opts)
|
|
129
|
+
return {};
|
|
130
|
+
let auth = {};
|
|
131
|
+
if (this.opts.expressConfig?.publicRoutes && !this.opts.expressConfig?.disableSocketAuthGuard) {
|
|
132
|
+
auth.pathGuard = true;
|
|
133
|
+
socket.removeAllListeners(prostgles_types_1.CHANNELS.AUTHGUARD);
|
|
134
|
+
socket.on(prostgles_types_1.CHANNELS.AUTHGUARD, async (params, cb = (err, res) => { }) => {
|
|
135
|
+
try {
|
|
136
|
+
const { pathname } = typeof params === "string" ? JSON.parse(params) : (params || {});
|
|
137
|
+
if (pathname && typeof pathname !== "string")
|
|
138
|
+
console.warn("Invalid pathname provided for AuthGuardLocation: ", pathname);
|
|
139
|
+
if (pathname && typeof pathname === "string" && this.isUserRoute(pathname) && !(await this.getClientInfo({ socket }))?.user) {
|
|
140
|
+
cb(null, { shouldReload: true });
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
cb(null, { shouldReload: false });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
console.error("AUTHGUARD err: ", err);
|
|
148
|
+
cb(err);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const { register, logout } = this.opts;
|
|
153
|
+
const login = this.loginThrottled;
|
|
154
|
+
let handlers = [
|
|
155
|
+
{ func: (params, dbo, db) => register?.(params, dbo, db), ch: prostgles_types_1.CHANNELS.REGISTER, name: "register" },
|
|
156
|
+
{ func: (params, dbo, db) => login(params), ch: prostgles_types_1.CHANNELS.LOGIN, name: "login" },
|
|
157
|
+
{ func: (params, dbo, db) => logout?.(this.getSID({ socket }), dbo, db), ch: prostgles_types_1.CHANNELS.LOGOUT, name: "logout" }
|
|
158
|
+
].filter(h => h.func);
|
|
159
|
+
const usrData = await this.getClientInfo({ socket });
|
|
160
|
+
if (usrData) {
|
|
161
|
+
auth.user = usrData.clientUser;
|
|
162
|
+
handlers = handlers.filter(h => h.name === "logout");
|
|
163
|
+
}
|
|
164
|
+
handlers.map(({ func, ch, name }) => {
|
|
165
|
+
auth[name] = true;
|
|
166
|
+
socket.removeAllListeners(ch);
|
|
167
|
+
socket.on(ch, async (params, cb = (...callback) => { }) => {
|
|
168
|
+
try {
|
|
169
|
+
if (!socket)
|
|
170
|
+
throw "socket missing??!!";
|
|
171
|
+
const res = await func(params, this.dbo, this.db);
|
|
172
|
+
if (name === "login" && res && res.sid) {
|
|
173
|
+
/* TODO: Re-send schema to client */
|
|
174
|
+
}
|
|
175
|
+
cb(null, true);
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
console.error(name + " err", err);
|
|
179
|
+
cb(err);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
return auth;
|
|
184
|
+
};
|
|
185
|
+
this.opts = prostgles.opts.auth;
|
|
186
|
+
if (prostgles.opts.auth?.expressConfig) {
|
|
187
|
+
this.returnURL = prostgles.opts.auth?.expressConfig?.returnURL || "returnURL";
|
|
188
|
+
this.loginRoute = prostgles.opts.auth?.expressConfig?.loginRoute || "/login";
|
|
189
|
+
this.logoutGetPath = prostgles.opts.auth?.expressConfig?.logoutGetPath || "/logout";
|
|
190
|
+
}
|
|
191
|
+
if (!prostgles.dbo || !prostgles.db)
|
|
192
|
+
throw "dbo or db missing";
|
|
193
|
+
this.dbo = prostgles.dbo;
|
|
194
|
+
this.db = prostgles.db;
|
|
195
|
+
}
|
|
196
|
+
async init() {
|
|
197
|
+
if (!this.opts)
|
|
198
|
+
return;
|
|
199
|
+
this.opts.sidKeyName = this.opts.sidKeyName || "session_id";
|
|
200
|
+
const { sidKeyName, login, getUser, expressConfig } = this.opts;
|
|
201
|
+
this.sidKeyName = this.opts.sidKeyName;
|
|
202
|
+
if (typeof sidKeyName !== "string" && !login) {
|
|
203
|
+
throw "Invalid auth: Provide { sidKeyName: string } ";
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Why ??? Collision with socket.io ???
|
|
207
|
+
*/
|
|
208
|
+
if (this.sidKeyName === "sid")
|
|
209
|
+
throw "sidKeyName cannot be 'sid' please provide another name.";
|
|
210
|
+
if (!getUser)
|
|
211
|
+
throw "getUser missing from auth config";
|
|
212
|
+
if (expressConfig) {
|
|
213
|
+
const { app, publicRoutes = [], onGetRequestOK, magicLinks } = expressConfig;
|
|
214
|
+
if (publicRoutes.find(r => typeof r !== "string" || !r)) {
|
|
215
|
+
throw "Invalid or empty string provided within publicRoutes ";
|
|
216
|
+
}
|
|
217
|
+
if (app && magicLinks) {
|
|
218
|
+
const { route = "/magic-link", check } = magicLinks;
|
|
219
|
+
if (!check)
|
|
220
|
+
throw "Check must be defined for magicLinks";
|
|
221
|
+
app.get(`${route}/:id`, async (req, res) => {
|
|
222
|
+
const { id } = req.params ?? {};
|
|
223
|
+
if (typeof id !== "string" || !id) {
|
|
224
|
+
res.status(404).json({ msg: "Invalid magic-link id. Expecting a string" });
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
try {
|
|
228
|
+
const session = await this.throttledFunc(async () => {
|
|
229
|
+
return check(id, this.dbo, this.db);
|
|
230
|
+
});
|
|
231
|
+
if (!session) {
|
|
232
|
+
res.status(404).json({ msg: "Invalid magic-link" });
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
this.setCookieAndGoToReturnURLIFSet(session, { req, res });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
catch (e) {
|
|
239
|
+
res.status(404).json({ msg: e });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
if (app && this.loginRoute) {
|
|
245
|
+
app.post(this.loginRoute, async (req, res) => {
|
|
246
|
+
try {
|
|
247
|
+
const { sid, expires } = await this.loginThrottled(req.body || {}) || {};
|
|
248
|
+
if (sid) {
|
|
249
|
+
this.setCookieAndGoToReturnURLIFSet({ sid, expires }, { req, res });
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
throw ("no user or session");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
console.log(err);
|
|
257
|
+
res.status(404).json({ err: "Invalid username or password" });
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
if (app && this.logoutGetPath && this.opts.logout) {
|
|
261
|
+
app.get(this.logoutGetPath, async (req, res) => {
|
|
262
|
+
const sid = this.validateSid(req?.cookies?.[sidKeyName]);
|
|
263
|
+
if (sid) {
|
|
264
|
+
try {
|
|
265
|
+
await this.throttledFunc(() => {
|
|
266
|
+
return this.opts.logout(req?.cookies?.[sidKeyName], this.dbo, this.db);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
console.error(err);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
res.redirect("/");
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
if (app && Array.isArray(publicRoutes)) {
|
|
277
|
+
/* Redirect if not logged in and requesting non public content */
|
|
278
|
+
app.get('*', async (req, res) => {
|
|
279
|
+
const clientReq = { httpReq: req };
|
|
280
|
+
const getUser = this.getUser;
|
|
281
|
+
try {
|
|
282
|
+
const returnURL = getReturnUrl(req, this.returnURL);
|
|
283
|
+
/**
|
|
284
|
+
* Requesting a User route
|
|
285
|
+
*/
|
|
286
|
+
if (this.isUserRoute(req.path)) {
|
|
287
|
+
/* Check auth. Redirect if unauthorized */
|
|
288
|
+
const u = await getUser(clientReq);
|
|
289
|
+
if (!u) {
|
|
290
|
+
res.redirect(`${this.loginRoute}?returnURL=${encodeURIComponent(req.originalUrl)}`);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
/* If authorized and going to returnUrl then redirect. Otherwise serve file */
|
|
294
|
+
}
|
|
295
|
+
else if (returnURL && (await getUser(clientReq))) {
|
|
296
|
+
res.redirect(returnURL);
|
|
297
|
+
return;
|
|
298
|
+
/** If Logged in and requesting login then redirect */
|
|
299
|
+
}
|
|
300
|
+
else if (this.matchesRoute(this.loginRoute, req.path) && (await getUser(clientReq))) {
|
|
301
|
+
res.redirect("/");
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (onGetRequestOK) {
|
|
305
|
+
onGetRequestOK(req, res);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
console.error(error);
|
|
310
|
+
res.status(404).json({ msg: "Something went wrong", error });
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Will return first sid value found in : http cookie or query params
|
|
319
|
+
* Based on sid names in auth
|
|
320
|
+
* @param localParams
|
|
321
|
+
* @returns string
|
|
322
|
+
*/
|
|
323
|
+
getSID(localParams) {
|
|
324
|
+
if (!this.opts)
|
|
325
|
+
return undefined;
|
|
326
|
+
const { sidKeyName } = this.opts;
|
|
327
|
+
if (!sidKeyName || !localParams)
|
|
328
|
+
return undefined;
|
|
329
|
+
if (localParams.socket) {
|
|
330
|
+
const querySid = localParams.socket?.handshake?.query?.[sidKeyName];
|
|
331
|
+
let rawSid = querySid;
|
|
332
|
+
if (!rawSid) {
|
|
333
|
+
const cookie_str = localParams.socket?.handshake?.headers?.cookie;
|
|
334
|
+
const cookie = parseCookieStr(cookie_str);
|
|
335
|
+
rawSid = cookie[sidKeyName];
|
|
336
|
+
}
|
|
337
|
+
return this.validateSid(rawSid);
|
|
338
|
+
}
|
|
339
|
+
else if (localParams.httpReq) {
|
|
340
|
+
return this.validateSid(localParams.httpReq?.cookies?.[sidKeyName]);
|
|
341
|
+
}
|
|
342
|
+
else
|
|
343
|
+
throw "socket OR httpReq missing from localParams";
|
|
344
|
+
function parseCookieStr(cookie_str) {
|
|
345
|
+
if (!cookie_str || typeof cookie_str !== "string")
|
|
346
|
+
return {};
|
|
347
|
+
return cookie_str.replace(/\s/g, '').split(";").reduce((prev, current) => {
|
|
348
|
+
const [name, value] = current.split('=');
|
|
349
|
+
prev[name] = value;
|
|
350
|
+
return prev;
|
|
351
|
+
}, {});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async getClientInfo(localParams) {
|
|
355
|
+
if (!this.opts)
|
|
356
|
+
return {};
|
|
357
|
+
const getSession = this.opts.cacheSession?.getSession;
|
|
358
|
+
const isSocket = "socket" in localParams;
|
|
359
|
+
if (getSession && isSocket && localParams.socket?.__prglCache) {
|
|
360
|
+
const { session, user, clientUser } = localParams.socket.__prglCache;
|
|
361
|
+
const isValid = this.isValidSocketSession(localParams.socket, session);
|
|
362
|
+
if (isValid) {
|
|
363
|
+
return {
|
|
364
|
+
sid: session.sid,
|
|
365
|
+
user,
|
|
366
|
+
clientUser,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
else
|
|
370
|
+
return {};
|
|
371
|
+
}
|
|
372
|
+
const res = await this.throttledFunc(async () => {
|
|
373
|
+
const { getUser } = this.opts ?? {};
|
|
374
|
+
if (getUser && localParams && (localParams.httpReq || localParams.socket)) {
|
|
375
|
+
const sid = this.getSID(localParams);
|
|
376
|
+
const clientReq = localParams.httpReq ? { httpReq: localParams.httpReq } : { socket: localParams.socket };
|
|
377
|
+
let user, clientUser;
|
|
378
|
+
if (sid) {
|
|
379
|
+
const res = await getUser(sid, this.dbo, this.db, clientReq);
|
|
380
|
+
user = res?.user;
|
|
381
|
+
clientUser = res?.clientUser;
|
|
382
|
+
}
|
|
383
|
+
if (getSession && isSocket) {
|
|
384
|
+
const session = await getSession(sid, this.dbo, this.db);
|
|
385
|
+
if (session?.expires && user && clientUser && localParams.socket) {
|
|
386
|
+
localParams.socket.__prglCache = {
|
|
387
|
+
session,
|
|
388
|
+
user,
|
|
389
|
+
clientUser,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (sid) {
|
|
394
|
+
return { sid, user, clientUser };
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return {};
|
|
398
|
+
}, 5);
|
|
399
|
+
return res;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
exports.default = AuthHandler;
|
|
403
|
+
/**
|
|
404
|
+
* AUTH
|
|
405
|
+
*/
|
|
406
|
+
function getReturnUrl(req, name) {
|
|
407
|
+
if (req?.query?.returnURL && name) {
|
|
408
|
+
return decodeURIComponent(req?.query?.[name]);
|
|
409
|
+
}
|
|
410
|
+
return null;
|
|
411
|
+
}
|
package/lib/AuthHandler.ts
CHANGED
|
@@ -36,7 +36,7 @@ export type BasicSession = {
|
|
|
36
36
|
|
|
37
37
|
};
|
|
38
38
|
export type AuthClientRequest = { socket: any } | { httpReq: ExpressReq }
|
|
39
|
-
export type Auth<S
|
|
39
|
+
export type Auth<S = void> = {
|
|
40
40
|
/**
|
|
41
41
|
* Name of the cookie or socket hadnshake query param that represents the session id.
|
|
42
42
|
* Defaults to "session_id"
|
|
@@ -136,8 +136,8 @@ export type ClientInfo = {
|
|
|
136
136
|
sid?: string;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
export default class AuthHandler
|
|
140
|
-
protected opts?: Auth
|
|
139
|
+
export default class AuthHandler {
|
|
140
|
+
protected opts?: Auth;
|
|
141
141
|
dbo: DBHandlerServer;
|
|
142
142
|
db: DB;
|
|
143
143
|
sidKeyName?: string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PostgresNotifListenManager } from "./PostgresNotifListenManager";
|
|
2
|
+
import { DB, PGP } from "./Prostgles";
|
|
3
|
+
import { PRGLIOSocket } from "./DboBuilder";
|
|
4
|
+
export declare class DBEventsManager {
|
|
5
|
+
notifies: {
|
|
6
|
+
[key: string]: {
|
|
7
|
+
socketChannel: string;
|
|
8
|
+
sockets: any[];
|
|
9
|
+
localFuncs: ((payload: string) => void)[];
|
|
10
|
+
notifMgr: PostgresNotifListenManager;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
notice: {
|
|
14
|
+
socketChannel: string;
|
|
15
|
+
socketUnsubChannel: string;
|
|
16
|
+
sockets: any[];
|
|
17
|
+
};
|
|
18
|
+
notifManager?: PostgresNotifListenManager;
|
|
19
|
+
db_pg: DB;
|
|
20
|
+
pgp: PGP;
|
|
21
|
+
constructor(db_pg: DB, pgp: PGP);
|
|
22
|
+
private onNotif;
|
|
23
|
+
onNotice: (notice: any) => void;
|
|
24
|
+
getNotifChannelName: (channel: string) => Promise<any>;
|
|
25
|
+
addNotify(query: string, socket?: PRGLIOSocket, func?: any): Promise<{
|
|
26
|
+
socketChannel: string;
|
|
27
|
+
socketUnsubChannel: string;
|
|
28
|
+
notifChannel: string;
|
|
29
|
+
unsubscribe?: () => void;
|
|
30
|
+
}>;
|
|
31
|
+
removeNotify(channel?: string, socket?: PRGLIOSocket, func?: any): void;
|
|
32
|
+
addNotice(socket: PRGLIOSocket): {
|
|
33
|
+
socketChannel: string;
|
|
34
|
+
socketUnsubChannel: string;
|
|
35
|
+
};
|
|
36
|
+
removeNotice(socket: PRGLIOSocket): void;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=DBEventsManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DBEventsManager.d.ts","sourceRoot":"","sources":["DBEventsManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAqB,MAAM,8BAA8B,CAAC;AAC7F,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,qBAAa,eAAe;IAE1B,QAAQ,EAAE;QACR,CAAC,GAAG,EAAE,MAAM,GAAG;YACb,aAAa,EAAE,MAAM,CAAC;YACtB,OAAO,EAAE,GAAG,EAAE,CAAC;YACf,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,EAAE,CAAC;YAC1C,QAAQ,EAAE,0BAA0B,CAAC;SACtC,CAAA;KACF,CAAM;IAEP,MAAM,EAAE;QACN,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,OAAO,EAAE,GAAG,EAAE,CAAC;KAChB,CAIC;IAEF,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAE1C,KAAK,EAAE,EAAE,CAAC;IACV,GAAG,EAAE,GAAG,CAAA;gBACI,KAAK,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG;IAK/B,OAAO,CAAC,OAAO,CAgBd;IAED,QAAQ,WAAY,GAAG,UAMtB;IAED,mBAAmB,YAAmB,MAAM,kBAG3C;IAEK,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC;QACzE,aAAa,EAAE,MAAM,CAAC;QACtB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;KAC1B,CAAC;IAmEF,YAAY,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,GAAG;IAkBhE,SAAS,CAAC,MAAM,EAAE,YAAY;;;;IAiB9B,YAAY,CAAC,MAAM,EAAE,YAAY;CAIlC"}
|