@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.166",
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",
@@ -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
 
@@ -16,4 +16,4 @@ export class PostChatterMessageDto {
16
16
  @IsString()
17
17
  @IsOptional()
18
18
  messageSubType?: string;
19
- }
19
+ }
@@ -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
- return {
6
- referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
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: 'same-site' },
9
- frameguard: { action: 'sameorigin' }, // or { action: 'deny' }
10
- // HSTS: send only in prod over HTTPS
11
- hsts:
12
- process.env.NODE_ENV === Environment.Production
13
- ? { maxAge: 31536000, includeSubDomains: true, preload: true } // 1 year
14
- : false,
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
- type Source = 'self' | 'none' | string; // string = an origin like 'https://cdn.example.com'
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: 'none',
25
- microphone: 'none',
26
- geolocation: 'none',
27
- fullscreen: 'self', // allow same-origin fullscreen
28
- payment: 'none',
29
- accelerometer: 'none',
30
- autoplay: 'none',
31
- 'clipboard-read': 'none',
32
- 'clipboard-write': 'none',
33
- gyroscope: 'none',
34
- magnetometer: 'none',
35
- usb: 'none',
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 === 'none') return '()';
49
- if (v === 'self') return '(self)';
50
- // array of sources: allow 'self' and/or explicit origins
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
- else {
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();