@opengis/fastify-table 1.5.9 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.js +28 -29
  2. package/dist/server/migrations/oauth.sql.sql +77 -0
  3. package/dist/server/plugins/auth/funcs/authorizeUser.js +63 -0
  4. package/dist/server/plugins/auth/funcs/checkReferer.js +24 -0
  5. package/dist/server/plugins/auth/funcs/getQuery.js +127 -0
  6. package/dist/server/plugins/auth/funcs/jwt.js +63 -0
  7. package/dist/server/plugins/auth/funcs/logAuth.js +17 -0
  8. package/dist/server/plugins/auth/funcs/loginFile.js +41 -0
  9. package/dist/server/plugins/auth/funcs/loginUser.js +45 -0
  10. package/dist/server/plugins/auth/funcs/sendNotification.js +96 -0
  11. package/dist/server/plugins/auth/funcs/users.js +2 -0
  12. package/dist/server/plugins/auth/funcs/verifyPassword.js +30 -0
  13. package/dist/server/plugins/auth/index.js +110 -0
  14. package/dist/server/plugins/policy/funcs/checkPolicy.js +33 -62
  15. package/dist/server/plugins/policy/index.js +2 -2
  16. package/dist/server/routes/access/controllers/access.group.post.js +3 -3
  17. package/dist/server/routes/auth/controllers/2factor/generate.js +38 -0
  18. package/dist/server/routes/auth/controllers/2factor/providers/totp.js +115 -0
  19. package/dist/server/routes/auth/controllers/2factor/recovery.js +83 -0
  20. package/dist/server/routes/auth/controllers/2factor/toggle.js +39 -0
  21. package/dist/server/routes/auth/controllers/2factor/verify.js +68 -0
  22. package/dist/server/routes/auth/controllers/core/getUserInfo.js +37 -0
  23. package/dist/server/routes/auth/controllers/core/login.js +21 -0
  24. package/dist/server/routes/auth/controllers/core/logout.js +10 -0
  25. package/dist/server/routes/auth/controllers/core/passwordRecovery.js +151 -0
  26. package/dist/server/routes/auth/controllers/core/registration.js +96 -0
  27. package/dist/server/routes/auth/controllers/core/updateUserInfo.js +17 -0
  28. package/dist/server/routes/auth/controllers/euSign/authByData.js +115 -0
  29. package/dist/server/routes/auth/controllers/jwt/authorize.js +78 -0
  30. package/dist/server/routes/auth/controllers/jwt/token.js +67 -0
  31. package/dist/server/routes/auth/controllers/page/login2faTemplate.js +70 -0
  32. package/dist/server/routes/auth/controllers/page/loginEuSign.js +20 -0
  33. package/dist/server/routes/auth/controllers/page/loginTemplate.js +45 -0
  34. package/dist/server/routes/auth/index.js +87 -0
  35. package/dist/server/routes/util/index.js +9 -5
  36. package/dist/server.js +62 -0
  37. package/package.json +19 -7
@@ -0,0 +1,20 @@
1
+ import path from "node:path";
2
+ import { readFile } from "node:fs/promises";
3
+ import { fileURLToPath } from "url";
4
+ import getTemplate from "../../../../plugins/table/funcs/getTemplate.js";
5
+ // relative default template filepath
6
+ const filename = fileURLToPath(import.meta.url);
7
+ const dirname = path.dirname(filename);
8
+ const headers = {
9
+ "Content-Type": "text/html; charset=UTF-8",
10
+ "Cache-Control": "no-cache",
11
+ "Accept-CH": "Viewport-Width, Width",
12
+ };
13
+ export default async function loginTemplate(req, reply) {
14
+ const body = await getTemplate("page", "loginEuSign");
15
+ if (!body) {
16
+ const defaultBody = await readFile(path.join(dirname, "../templates/page/loginEuSign.html"), "utf8");
17
+ return reply.headers(headers).send(defaultBody);
18
+ }
19
+ return reply.headers(headers).send(body);
20
+ }
@@ -0,0 +1,45 @@
1
+ import path from "node:path";
2
+ import { readFile } from "node:fs/promises";
3
+ import { fileURLToPath } from "url";
4
+ import config from "../../../../../config.js";
5
+ import { handlebars } from "../../../../helpers/index.js";
6
+ import pgClients from "../../../../plugins/pg/pgClients.js";
7
+ import getTemplate from "../../../../plugins/table/funcs/getTemplate.js";
8
+ // relative default template filepath
9
+ const filename = fileURLToPath(import.meta.url);
10
+ const dirname = path.dirname(filename);
11
+ const headers = {
12
+ "Content-Type": "text/html; charset=UTF-8",
13
+ "Cache-Control": "no-cache",
14
+ "Accept-CH": "Viewport-Width, Width",
15
+ };
16
+ export default async function loginTemplate(req, reply) {
17
+ const { pg = pgClients.client } = req;
18
+ const body = await getTemplate("page", "login");
19
+ const { rows = [] } = config.pg
20
+ ? await pg.query("select property_key as key, property_text as val from admin.properties where property_key is not null")
21
+ : {};
22
+ const settings = rows.reduce((p, { key, val }) => {
23
+ const [k1, k2] = key.split(".");
24
+ p[k1] = p[k1] || {};
25
+ p[k1][k2] = val;
26
+ return p;
27
+ }, {});
28
+ if (!body) {
29
+ const defaultBody = await readFile(path.join(dirname, "../templates/page/login.html"), "utf8");
30
+ const html = await handlebars.compile(defaultBody)({
31
+ settings,
32
+ req,
33
+ hostname: req.hostname,
34
+ config,
35
+ });
36
+ return reply.headers(headers).send(html);
37
+ }
38
+ const html = await handlebars.compile(body)({
39
+ settings,
40
+ req,
41
+ hostname: req.hostname,
42
+ config,
43
+ });
44
+ return reply.headers(headers).send(html);
45
+ }
@@ -0,0 +1,87 @@
1
+ // import fp from "fastify-plugin";
2
+ import config from "../../../config.js";
3
+ // login-password
4
+ import login from "./controllers/core/login.js";
5
+ import registration from "./controllers/core/registration.js";
6
+ import passwordRecovery from "./controllers/core/passwordRecovery.js";
7
+ // euSign
8
+ import authByData from "./controllers/euSign/authByData.js";
9
+ // utils
10
+ import logout from "./controllers/core/logout.js";
11
+ import getUserInfo from "./controllers/core/getUserInfo.js";
12
+ import updateUserInfo from "./controllers/core/updateUserInfo.js";
13
+ // 2factor / totp
14
+ import verify from "./controllers/2factor/verify.js";
15
+ import recovery from "./controllers/2factor/recovery.js";
16
+ // pages
17
+ import loginTemplate from "./controllers/page/loginTemplate.js";
18
+ import login2faTemplate from "./controllers/page/login2faTemplate.js";
19
+ // jwt
20
+ import oauthAuthorize from "./controllers/jwt/authorize.js";
21
+ import oauthToken from "./controllers/jwt/token.js";
22
+ const params = { config: { policy: "L0" } };
23
+ async function plugin(app, opt = config) {
24
+ if (opt.routes === false) {
25
+ return;
26
+ }
27
+ if (!app.hasRoute({ method: "GET", url: "/logout" })) {
28
+ app.get("/logout", params, logout);
29
+ }
30
+ if (!app.hasRoute({ method: "GET", url: "/api/login" })) {
31
+ app.get("/api/login", params, login);
32
+ }
33
+ if (!app.hasRoute({ method: "POST", url: "/api/login" })) {
34
+ app.post("/api/login", params, login);
35
+ }
36
+ if (!app.hasRoute({ method: "POST", url: "/api/registration" })) {
37
+ app.post("/api/registration", params, registration);
38
+ }
39
+ if (!app.hasRoute({ method: "POST", url: "/api/recovery" })) {
40
+ app.post("/api/recovery", params, passwordRecovery);
41
+ }
42
+ // 2factor
43
+ if (!app.hasRoute({ method: "GET", url: "/2factor/verify" })) {
44
+ app.post("/2factor/verify", params, verify);
45
+ }
46
+ if (!app.hasRoute({ method: "POST", url: "/2factor/recovery" })) {
47
+ app.post("/2factor/recovery", params, recovery);
48
+ }
49
+ if (!app.hasRoute({ method: "GET", url: "/2factor/recovery" })) {
50
+ app.get("/2factor/recovery", params, recovery);
51
+ }
52
+ // get/edit user info
53
+ if (!app.hasRoute({ method: "GET", url: "/user" })) {
54
+ app.get("/user", params, getUserInfo);
55
+ }
56
+ if (!app.hasRoute({ method: "POST", url: "/user" })) {
57
+ app.post("/user", { config: { auth: "creds" } }, updateUserInfo);
58
+ }
59
+ // jwt
60
+ if (!app.hasRoute({ method: "GET", url: "/oauth/authorize" })) {
61
+ app.get("/oauth/authorize", params, oauthAuthorize);
62
+ }
63
+ if (!app.hasRoute({ method: "GET", url: "/oauth/token" })) {
64
+ app.get("/oauth/token", params, oauthToken);
65
+ }
66
+ if (!app.hasRoute({ method: "POST", url: "/oauth/token" })) {
67
+ app.post("/oauth/token", params, oauthToken);
68
+ }
69
+ // euSign
70
+ if (!app.hasRoute({ method: "GET", url: "/auth/by_data" }) &&
71
+ !opt.auth?.customRoutes &&
72
+ !opt.auth?.customGovId) {
73
+ app.get("/auth/by_data", params, authByData);
74
+ }
75
+ // pages
76
+ if (!app.hasRoute({ method: "GET", url: "/2factor" }) &&
77
+ !opt.auth?.disable &&
78
+ !opt.auth?.login2factorPage) {
79
+ app.get("/2factor", params, login2faTemplate);
80
+ }
81
+ if (!app.hasRoute({ method: "GET", url: "/login" }) &&
82
+ !opt.auth?.disable &&
83
+ !opt?.auth?.loginPage) {
84
+ app.get("/login", params, loginTemplate);
85
+ }
86
+ }
87
+ export default plugin;
@@ -1,13 +1,17 @@
1
- // import type { FastifyInstance } from 'fastify';
2
1
  import nextId from "./controllers/next.id.js";
3
2
  import statusMonitor from "./controllers/status.monitor.js";
4
3
  import userTokens from "./controllers/user.tokens.js";
5
4
  import codeGenerator from "./controllers/code.generator.js";
6
5
  async function plugin(app, config = { prefix: "/api" }) {
7
6
  const { prefix = "/api" } = config;
8
- app.get(`${prefix}/next-id`, { config: { policy: ["public"] } }, nextId);
9
- app.get(`${prefix}/status-monitor`, {}, statusMonitor);
10
- app.get(`${prefix}/user-tokens/:token`, { config: { policy: ["user", "site"] } }, userTokens);
11
- app.get(`${prefix}/code-gen/:token/:column/:id?`, { config: { policy: ["user"] } }, codeGenerator);
7
+ app.get(`${prefix}/next-id`, { config: { policy: "L0" } }, nextId);
8
+ app.get(`${prefix}/status-monitor`, { config: { role: "admin" } }, statusMonitor);
9
+ app.get(`${prefix}/user-tokens/:token`, { config: { role: "admin|regular" } }, userTokens);
10
+ app.get(`${prefix}/code-gen/:token/:column/:id?`, { config: { role: "admin|regular" } }, codeGenerator);
11
+ app.get("/api/test-proxy", { config: { policy: "L0" } }, (req) => ({
12
+ ...(req.headers || {}),
13
+ sessionId: req.session?.sessionId,
14
+ }));
15
+ app.get("/api/config", { config: { role: "admin" } }, () => config);
12
16
  }
13
17
  export default plugin;
package/dist/server.js ADDED
@@ -0,0 +1,62 @@
1
+ /* eslint-disable no-return-assign */
2
+ // This file contains code that we reuse
3
+ // between our tests.
4
+ import Fastify from 'fastify';
5
+
6
+ import config from './config.js';
7
+ import plugin from './index.js';
8
+ import addHook from "./server/plugins/hook/funcs/addHook.js";
9
+ import loginEuSign from './server/routes/auth/controllers/page/loginEuSign.js';
10
+
11
+ import loggerTest from './server/routes/logger/controllers/logger.test.api.js';
12
+ import { logger, addTemplateDir } from './utils.js';
13
+
14
+ const cwd = process.cwd();
15
+
16
+ const app = Fastify({ loggerInstance: logger });
17
+ await app.register(plugin, config);
18
+
19
+ // debug only
20
+ app.get('/login1', { config: { policy: 'L0' } }, loginEuSign);
21
+ addHook("afterAuth", async () => {
22
+ if (config.auth?.redirectAfter) return; // let config decide
23
+ return { href: "/user" }; // force redirect to specific page after login
24
+ });
25
+
26
+ addTemplateDir(`${cwd}/module/test`);
27
+
28
+ app.get('/logger-test', { schema: {} }, loggerTest);
29
+ app.get('/err', { schema: {} }, () => {
30
+ throw new Error('test error code 500');
31
+ });
32
+
33
+ app.get('/health', {
34
+ // preHandler: userJwt,
35
+ config: {
36
+ policy: 'L1', // L0, L1, L2
37
+ auth: 'user-jwt', // none, user-jwt, creds
38
+ role: 'admin', // role
39
+ scope: 'logger', // logger, admin, gis, bi
40
+ rateLimit: { max: 100, timeWindow: '1 minute', hook: 'preHandler' },
41
+ cors: { origins: ['https://app.example.com'] },
42
+ rbac: { resource: 'id', action: 'add' },
43
+ }
44
+ }, async () => ({ ok: true }));
45
+
46
+ /* addCron(async function testCron() {
47
+ return (config.local || true) ? null : { message: 'Done', status: 200 };
48
+ }, 60 * 1); */
49
+
50
+ /* const user = { user_type: config.auth?.type || 'admin', uid: config.auth?.uid || '2' };
51
+ app.addHook('onRequest', async (req) => {
52
+ req.user = user;
53
+ }); */
54
+
55
+ app.listen({ host: config.host || '0.0.0.0', port: config.port || process.env.PORT || 3000 }, (err) => {
56
+ console.log(`Server started via port: ${config.port || process.env.PORT || 3000}`);
57
+ if (err) {
58
+ console.error(err.toString());
59
+ logger.error(err);
60
+ process.exit(1);
61
+ }
62
+ });
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@opengis/fastify-table",
3
- "version": "1.5.9",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "description": "core-plugins",
6
6
  "keywords": [
7
7
  "fastify",
8
8
  "table",
9
9
  "crud",
10
+ "auth",
10
11
  "pg",
11
12
  "backend"
12
13
  ],
@@ -28,34 +29,41 @@
28
29
  "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
29
30
  "test": "node --test",
30
31
  "compress": "node compress.js",
31
- "dev1": "set NODE_ENV=local&& node server.js",
32
+ "dev1": "bun --hot dist/server",
32
33
  "dev": "NODE_ENV=production bun start",
33
34
  "start": "bun server"
34
35
  },
35
36
  "dependencies": {
36
37
  "@aws-sdk/client-s3": "3.879.0",
37
38
  "@aws-sdk/lib-storage": "3.879.0",
39
+ "@fastify/cookie": "11.0.2",
38
40
  "@fastify/http-proxy": "11.1.2",
39
41
  "@fastify/multipart": "9.0.3",
42
+ "@fastify/passport": "3.0.2",
40
43
  "@fastify/rate-limit": "10.3.0",
41
- "@grpc/grpc-js": "1.10.6",
42
- "@grpc/proto-loader": "0.7.12",
44
+ "@fastify/session": "11.1.0",
45
+ "@grpc/grpc-js": "1.10.11",
46
+ "@grpc/proto-loader": "0.7.15",
47
+ "apache-crypt": "1.2.6",
43
48
  "better-sqlite3": "12.2.0",
44
- "copyfiles": "^2.4.1",
45
49
  "dotenv": "16.5.0",
46
50
  "fastify": "5.3.3",
47
51
  "fastify-plugin": "5.0.1",
52
+ "fastify-session-redis-store": "7.1.2",
48
53
  "handlebars": "4.7.8",
49
54
  "image-size": "1.2.0",
50
55
  "ioredis": "5.3.2",
51
56
  "js-yaml": "4.1.0",
52
57
  "markdown-it": "14.1.0",
53
- "pg": "8.11.3",
58
+ "nodemailer": "7.0.6",
59
+ "otplib": "12.0.1",
60
+ "pg": "8.11.6",
54
61
  "pino": "9.5.0",
55
62
  "pino-abstract-transport": "2.0.0",
56
63
  "promised-handlebars": "2.0.1",
57
64
  "qrcode": "1.5.4",
58
- "uglify-js": "3.19.3"
65
+ "uglify-js": "3.19.3",
66
+ "undici": "7.16.0"
59
67
  },
60
68
  "devDependencies": {
61
69
  "@types/better-sqlite3": "^7.6.13",
@@ -63,8 +71,12 @@
63
71
  "@types/js-yaml": "^4.0.9",
64
72
  "@types/markdown-it": "^14.1.2",
65
73
  "@types/node": "^24.3.1",
74
+ "@types/nodemailer": "^7.0.1",
75
+ "@types/passport": "^1.0.17",
76
+ "@types/passport-local": "^1.0.38",
66
77
  "@types/pg": "^8.15.5",
67
78
  "@types/qrcode": "^1.5.5",
79
+ "copyfiles": "^2.4.1",
68
80
  "eslint": "^9.35.0",
69
81
  "eslint-config-airbnb-extended": "^2.3.1",
70
82
  "ts-migrate": "^0.1.35",