@solidstarters/solid-core 1.2.166 → 1.2.168
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/config/iam.config.d.ts +2 -0
- package/dist/config/iam.config.d.ts.map +1 -1
- package/dist/config/iam.config.js +1 -0
- package/dist/config/iam.config.js.map +1 -1
- package/dist/dtos/post-chatter-message.dto.js.map +1 -1
- package/dist/entities/chatter-message.entity.js.map +1 -1
- package/dist/helpers/security.helper.d.ts +4 -2
- package/dist/helpers/security.helper.d.ts.map +1 -1
- package/dist/helpers/security.helper.js +38 -23
- package/dist/helpers/security.helper.js.map +1 -1
- package/dist/services/authentication.service.js +2 -1
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/model-metadata.service.js +1 -1
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/setting.service.d.ts.map +1 -1
- package/dist/services/setting.service.js +2 -1
- package/dist/services/setting.service.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config/iam.config.ts +1 -0
- package/src/dtos/post-chatter-message.dto.ts +1 -1
- package/src/entities/chatter-message.entity.ts +3 -3
- package/src/helpers/security.helper.ts +95 -30
- package/src/services/authentication.service.ts +2 -2
- package/src/services/chatter-message.service.ts +373 -374
- package/src/services/model-metadata.service.ts +1 -1
- package/src/services/setting.service.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidstarters/solid-core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.168",
|
|
4
4
|
"description": "This module is a NestJS module containing all the required core providers required by a Solid application",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
package/src/config/iam.config.ts
CHANGED
|
@@ -22,6 +22,7 @@ export const iamConfig = registerAs('iam', () => {
|
|
|
22
22
|
callbackURL: process.env.IAM_GOOGLE_OAUTH_CALLBACK_URL,
|
|
23
23
|
redirectURL: process.env.IAM_GOOGLE_OAUTH_REDIRECT_URL,
|
|
24
24
|
},
|
|
25
|
+
iamAutoGeneratedPassword:process.env.IAM_AUTOGENERATED_PASSWORD || true
|
|
25
26
|
};
|
|
26
27
|
})
|
|
27
28
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { CommonEntity } from 'src/entities/common.entity'
|
|
2
|
-
import {Entity, Column, Index, JoinColumn, ManyToOne} from 'typeorm';
|
|
2
|
+
import { Entity, Column, Index, JoinColumn, ManyToOne } from 'typeorm';
|
|
3
3
|
import { User } from 'src/entities/user.entity'
|
|
4
4
|
|
|
5
5
|
@Entity("ss_chatter_message")
|
|
6
6
|
export class ChatterMessage extends CommonEntity {
|
|
7
7
|
@Index()
|
|
8
8
|
@Column({ type: "varchar" })
|
|
9
|
-
messageType: string;
|
|
9
|
+
messageType: string; // audit | custom
|
|
10
10
|
@Column({ type: "varchar" })
|
|
11
|
-
messageSubType: string;
|
|
11
|
+
messageSubType: string; // update | insert | delete | post_message
|
|
12
12
|
@Column({ type: "text" })
|
|
13
13
|
messageBody: string;
|
|
14
14
|
@Index()
|
|
@@ -1,38 +1,74 @@
|
|
|
1
|
+
import { HelmetOptions } from "helmet";
|
|
1
2
|
import { Environment } from "src/decorators/disallow-in-production.decorator";
|
|
2
|
-
import { HelmetOptions } from "helmet";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Default security headers for SolidX apps.
|
|
6
|
+
* - HSTS only in prod over HTTPS
|
|
7
|
+
* - CSP with frame-ancestors 'none' (prevents clickjacking)
|
|
8
|
+
* - X-Frame-Options: DENY (legacy fallback)
|
|
9
|
+
* - No X-XSS-Protection (deprecated)
|
|
10
|
+
*/
|
|
4
11
|
export function buildDefaultSecurityHeaderOptions(): Readonly<HelmetOptions> {
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
const isProd = process.env.ENV === Environment.Production;
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
// Modern CSP. Add more directives as your app needs (script-src, connect-src, etc.)
|
|
16
|
+
contentSecurityPolicy: {
|
|
17
|
+
useDefaults: true,
|
|
18
|
+
directives: {
|
|
19
|
+
// sensible secure defaults
|
|
20
|
+
// "default-src": ["'self'"],
|
|
21
|
+
// "base-uri": ["'self'"],
|
|
22
|
+
// "object-src": ["'none'"],
|
|
23
|
+
// "form-action": ["'self'"],
|
|
24
|
+
|
|
25
|
+
// clickjacking defense (modern)
|
|
26
|
+
"frame-ancestors": ["'none'"],
|
|
27
|
+
|
|
28
|
+
// add/adjust as needed for your app:
|
|
29
|
+
// "script-src": ["'self'"], // add hashes/nonces/CSPRO if needed
|
|
30
|
+
// "style-src": ["'self'", "'unsafe-inline'"],
|
|
31
|
+
// "img-src": ["'self'", "data:"],
|
|
32
|
+
// "connect-src": ["'self'", "https://api.example.com"],
|
|
33
|
+
// "frame-src": ["'none'"], // iframes you intentionally allow
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
// Legacy clickjacking defense (kept for older UAs)
|
|
39
|
+
frameguard: { action: "deny" },
|
|
40
|
+
|
|
41
|
+
// Referrer/cross-origin policies
|
|
42
|
+
referrerPolicy: { policy: "strict-origin-when-cross-origin" },
|
|
7
43
|
crossOriginEmbedderPolicy: false,
|
|
8
|
-
crossOriginResourcePolicy: { policy:
|
|
9
|
-
|
|
10
|
-
// HSTS
|
|
11
|
-
hsts:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
44
|
+
crossOriginResourcePolicy: { policy: "same-site" },
|
|
45
|
+
|
|
46
|
+
// HSTS only when you’re on HTTPS in production
|
|
47
|
+
hsts: isProd
|
|
48
|
+
? { maxAge: 31536000, includeSubDomains: true, preload: true }
|
|
49
|
+
: false,
|
|
50
|
+
};
|
|
16
51
|
}
|
|
17
52
|
|
|
18
|
-
|
|
19
|
-
type DirectiveConfig = 'self' | 'none' | Source[];
|
|
53
|
+
/* ---------------- Permissions-Policy (formerly Feature-Policy) ---------------- */
|
|
20
54
|
|
|
55
|
+
type Source = "self" | "none" | string;
|
|
56
|
+
type DirectiveConfig = "self" | "none" | Source[];
|
|
21
57
|
export type PermissionsPolicyConfig = Record<string, DirectiveConfig>;
|
|
22
58
|
|
|
23
59
|
export const DEFAULT_PERMISSIONS_POLICY: PermissionsPolicyConfig = {
|
|
24
|
-
camera:
|
|
25
|
-
microphone:
|
|
26
|
-
geolocation:
|
|
27
|
-
fullscreen:
|
|
28
|
-
payment:
|
|
29
|
-
accelerometer:
|
|
30
|
-
autoplay:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
gyroscope:
|
|
34
|
-
magnetometer:
|
|
35
|
-
usb:
|
|
60
|
+
camera: "none",
|
|
61
|
+
microphone: "none",
|
|
62
|
+
geolocation: "none",
|
|
63
|
+
fullscreen: "self",
|
|
64
|
+
payment: "none",
|
|
65
|
+
accelerometer: "none",
|
|
66
|
+
autoplay: "none",
|
|
67
|
+
"clipboard-read": "none",
|
|
68
|
+
"clipboard-write": "none",
|
|
69
|
+
gyroscope: "none",
|
|
70
|
+
magnetometer: "none",
|
|
71
|
+
usb: "none",
|
|
36
72
|
};
|
|
37
73
|
|
|
38
74
|
export function buildPermissionsPolicyHeader(
|
|
@@ -41,13 +77,42 @@ export function buildPermissionsPolicyHeader(
|
|
|
41
77
|
const merged: PermissionsPolicyConfig = { ...DEFAULT_PERMISSIONS_POLICY, ...overrides };
|
|
42
78
|
return Object.entries(merged)
|
|
43
79
|
.map(([feature, value]) => `${feature}=${serializeValue(value)}`)
|
|
44
|
-
.join(
|
|
80
|
+
.join(", ");
|
|
45
81
|
}
|
|
46
82
|
|
|
47
83
|
function serializeValue(v: DirectiveConfig): string {
|
|
48
|
-
if (v ===
|
|
49
|
-
if (v ===
|
|
50
|
-
|
|
51
|
-
const parts = v.map(src => (src === 'self' ? 'self' : src)).join(' ');
|
|
84
|
+
if (v === "none") return "()";
|
|
85
|
+
if (v === "self") return "(self)";
|
|
86
|
+
const parts = v.map((src) => (src === "self" ? "self" : src)).join(" ");
|
|
52
87
|
return `(${parts})`;
|
|
53
88
|
}
|
|
89
|
+
|
|
90
|
+
/* ---------------- Cache-Control helpers ---------------- */
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Default: no-store for HTML/API responses unless you have a reason to cache.
|
|
94
|
+
* Attach as a global middleware or on selected routes.
|
|
95
|
+
*/
|
|
96
|
+
export const DEFAULT_CACHE_CONTROL =
|
|
97
|
+
"no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0, s-maxage=0";
|
|
98
|
+
|
|
99
|
+
export function setDefaultCacheControl() {
|
|
100
|
+
return function cacheControlMiddleware(
|
|
101
|
+
_req: import("express").Request,
|
|
102
|
+
_res: import("express").Response,
|
|
103
|
+
next: import("express").NextFunction
|
|
104
|
+
) {
|
|
105
|
+
_res.setHeader("Cache-Control", DEFAULT_CACHE_CONTROL);
|
|
106
|
+
next();
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ---------------- Example Express wiring ---------------- */
|
|
111
|
+
// import express from "express";
|
|
112
|
+
// const app = express();
|
|
113
|
+
// app.use(helmet(buildDefaultSecurityHeaderOptions()));
|
|
114
|
+
// app.use((req, res, next) => {
|
|
115
|
+
// res.setHeader("Permissions-Policy", buildPermissionsPolicyHeader());
|
|
116
|
+
// next();
|
|
117
|
+
// });
|
|
118
|
+
// app.use(setDefaultCacheControl());
|
|
@@ -196,7 +196,7 @@ export class AuthenticationService {
|
|
|
196
196
|
|
|
197
197
|
private async populateForSignup<T extends User>(user: T, signUpDto: SignUpDto, isUserActive: boolean = true, onForcePasswordChange?: boolean) {
|
|
198
198
|
// const user = new User();
|
|
199
|
-
|
|
199
|
+
let autoGeneratedPwdPermission = await this.settingService.getConfigValue('iamAutoGeneratedPassword');
|
|
200
200
|
if (signUpDto.roles && signUpDto.roles.length > 0) {
|
|
201
201
|
for (let i = 0; i < signUpDto.roles.length; i++) {
|
|
202
202
|
const roleName = signUpDto.roles[i];
|
|
@@ -217,7 +217,7 @@ export class AuthenticationService {
|
|
|
217
217
|
if (signUpDto.password) {
|
|
218
218
|
pwd = await this.hashingService.hash(signUpDto.password);
|
|
219
219
|
}
|
|
220
|
-
|
|
220
|
+
if(autoGeneratedPwdPermission?.toString().toLowerCase() === 'true'){
|
|
221
221
|
// TODO: If password is not specified then auto-generate a random password, trigger this password over an email to the user.
|
|
222
222
|
// TODO: Also track if the user has to force reset / change their password, and then activate the user.
|
|
223
223
|
autoGeneratedPwd = this.generatePassword();
|