@carecard/auth-util 3.1.15 → 3.2.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.
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: npm-package-flow
3
+ description: 'Use in pkg-* repositories when publishable package code changes require a version bump, GitHub development/main squash-merge flow, npm publication, and uncommitted consumer package updates in ms-* and app-dashboard.'
4
+ ---
5
+
6
+ # npm Package Flow
7
+
8
+ ## Purpose
9
+
10
+ Use this skill in a `pkg-*` repository when package code changes need to be
11
+ published to npm and propagated to CareCard consumers.
12
+
13
+ The package name is the `name` field in the repository `package.json`.
14
+
15
+ ## Publishable vs Non-Publishable Changes
16
+
17
+ Publishable package changes include runtime source changes, public exports,
18
+ TypeScript declarations, package metadata that affects consumers, security
19
+ behavior, or dependency behavior that changes the package contract.
20
+
21
+ The following are not publishable package changes by themselves:
22
+
23
+ - Skills or `.agents` guidance.
24
+ - Documentation and README updates.
25
+ - Tests, fixtures, mocks, snapshots, or validation-only changes.
26
+ - Formatting-only changes and comments.
27
+
28
+ For non-publishable changes, do not bump the package version, publish to npm,
29
+ or update `ms-*` and `app-dashboard` package versions.
30
+
31
+ ## Required Flow For Publishable Changes
32
+
33
+ Run this workflow only when the user explicitly asks for package publication,
34
+ remote GitHub merge work, or the full package-flow completion. Remote Git and
35
+ GitHub operations must not be inferred.
36
+
37
+ 1. Finish package code, tests, documentation, and skill updates inside the
38
+ current `pkg-*` repository.
39
+ 2. Bump the package version in `package.json` and `package-lock.json` according
40
+ to the user request or the package change scope.
41
+ 3. Run the package's required tests, lint, type checks, and every direct Husky
42
+ script. Fix failures before continuing.
43
+ 4. Commit the package changes to the current branch.
44
+ 5. Push the current branch, create or reuse the PR into `development`,
45
+ squash-merge it with administrator privileges, and delete the merged branch.
46
+ 6. Create a new merge branch from the updated `development` branch and use that
47
+ branch to open a PR into `main`.
48
+ 7. Squash-merge the merge branch into `main` with administrator privileges and
49
+ delete the merge branch. This `main` merge publishes the package.
50
+ 8. Confirm publication with `npm view <package-name>@<version> version`.
51
+ 9. Check out a fresh local branch with the same name as the deleted working
52
+ branch from the updated `development` branch.
53
+ 10. Update the new `@carecard/...` package version in `app-dashboard` and in
54
+ only the `ms-*` repositories that already declare the package, plus any
55
+ explicitly intended new consumers.
56
+ 11. Run `npm install` and relevant validation in each updated consumer.
57
+ 12. Do not commit the `ms-*` or `app-dashboard` consumer updates unless the user
58
+ explicitly asks.
59
+
60
+ ## Consumer Update Rules
61
+
62
+ - Discover existing consumers by checking each target repository `package.json`
63
+ for the published package name.
64
+ - Install exact package versions, for example
65
+ `npm install <package-name>@<version> --save-exact`.
66
+ - Keep consumer updates local and uncommitted unless the user gives a separate
67
+ commit or PR instruction.
68
+ - If a consumer should become a new dependency, require explicit user intent for
69
+ that repository.
70
+
71
+ ## Reporting
72
+
73
+ Report the package name, published version, development PR, main PR, npm
74
+ publication check, consumer repositories updated, validation commands run, and
75
+ any consumer updates intentionally left uncommitted.
@@ -0,0 +1,5 @@
1
+ interface:
2
+ display_name: 'npm Package Flow'
3
+ short_description: 'Use in pkg-* repositories when publishable @carecard package code changes need npm publication and consumer updates.'
4
+ brand_color: '#0F766E'
5
+ default_prompt: 'Use $npm-package-flow when this task matches the skill scope.'
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: pkg-auth-util-auth-crypto-library
3
- description: Use when changing pkg-auth-util auth, password, JWT, crypto, key, exported API, types, or package validation behavior.
3
+ description: 'Use when changing pkg-auth-util auth, password, JWT, crypto, key, exported API, types, or package validation behavior.'
4
4
  ---
5
5
 
6
6
  # Package Auth Util
@@ -43,8 +43,8 @@ CareCard auth utility package for JWT creation/verification primitives, password
43
43
 
44
44
  ## Safety Constraints
45
45
 
46
- - Do not edit generated output, dependency folders, logs, coverage, dist, or build artifacts unless the task explicitly requires it.
47
- - Do not revert or overwrite user changes; stage only files related to the requested skill or instruction update.
46
+ - Do not edit generated output, dependency folders, logs, coverage, dist, or build artifacts unless the task requires it.
47
+ - Do not revert or overwrite user changes; stage only requested skill or instruction files.
48
48
  - Never suppress errors, lint failures, type failures, security failures, or failing tests; fix the underlying issue or report the blocker.
49
49
  - Do not log or expose secrets, JWTs, passwords, credentials, private keys, sensitive personal data, SQL internals, or stack traces.
50
50
 
@@ -107,6 +107,9 @@ depend on those folders being present.
107
107
  `jwtCreateServiceAuthorizationHeader`.
108
108
  - Do not silently change token timing behavior, token formats, JWT string
109
109
  assembly, signature verification semantics, or decomposition return shapes.
110
+ - Preserve application JWT payload claims, including the `roles` array.
111
+ `ms-auth` RLS treats `roles: ["ad"]` as the auth-service super-admin signal,
112
+ so JWT helpers must not hide, rename, or drop that role data.
110
113
  - Expected parse and verify failures should return `null` or `false` where the
111
114
  current public API does so.
112
115
 
@@ -146,7 +149,7 @@ depend on those folders being present.
146
149
  - Use `try/catch` inside utility functions where existing functions fail
147
150
  gracefully instead of throwing uncaught exceptions.
148
151
  - Do not broaden catch blocks in a way that hides unexpected implementation
149
- errors in callers that currently expect throws.
152
+ errors in callers that expect throws.
150
153
 
151
154
  ## Types And Exports
152
155
 
@@ -199,7 +202,7 @@ and remaining risk.
199
202
 
200
203
  ## Remote Git Operations Guardrail
201
204
 
202
- Do not run remote Git or GitHub operations unless the current user request explicitly asks for that remote operation. This includes `git fetch`, `git pull`, `git push`, `git push --delete`, remote branch cleanup, GitHub API calls, and any `gh pr` command that creates, updates, readies, merges, closes, or cleans up a pull request. Do not infer permission from branch names, validation needs, prior workflow habits, or convenience; ask first when remote state would be useful but was not requested.
205
+ Do not run remote Git or GitHub operations unless the current user request explicitly asks for them. This includes `git fetch`, `git pull`, `git push`, `git push --delete`, remote branch cleanup, GitHub API calls, and any `gh pr` command that creates, updates, readies, merges, closes, or cleans up a pull request. Do not infer permission from branch names, validation needs, prior workflow habits, or convenience; ask first when remote state would help but was not requested.
203
206
 
204
207
  ## Agent Guidance Git Workflow
205
208
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: software-design-patterns-and-clean-code
3
- description: Use every time before coding, refactoring, debugging, or reviewing in this repository, alongside all other applicable skills, to apply pragmatic software design patterns, SOLID, Clean Code, and testable architecture.
3
+ description: 'Use every time before coding, refactoring, debugging, or reviewing in this repository, alongside all other applicable skills, to apply pragmatic software design patterns, SOLID, Clean Code, and testable architecture.'
4
4
  ---
5
5
 
6
6
  # Software Design Patterns And Clean Code
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carecard/auth-util",
3
- "version": "3.1.15",
3
+ "version": "3.2.0",
4
4
  "repository": "https://github.com/CareCard-ca/pkg-auth-util.git",
5
5
  "description": "Auth utility functions",
6
6
  "main": "index.js",
@@ -25,24 +25,24 @@
25
25
  "author": "CareCard team",
26
26
  "license": "ISC",
27
27
  "devDependencies": {
28
- "express": "5.2.1",
29
28
  "@istanbuljs/nyc-config-typescript": "1.0.2",
29
+ "@types/express": "5.0.6",
30
30
  "@types/mocha": "10.0.10",
31
31
  "@types/node": "25.9.1",
32
- "@types/express": "5.0.6",
32
+ "eslint": "9.39.4",
33
+ "express": "5.2.1",
33
34
  "husky": "9.1.7",
35
+ "lint-staged": "17.0.5",
34
36
  "mocha": "11.7.6",
35
37
  "nyc": "18.0.0",
36
38
  "prettier": "3.8.3",
37
- "eslint": "9.39.4",
38
- "lint-staged": "17.0.5",
39
39
  "source-map-support": "0.5.21",
40
40
  "supertest": "7.2.2",
41
41
  "ts-node": "10.9.2",
42
42
  "typescript": "6.0.3"
43
43
  },
44
44
  "dependencies": {
45
- "@carecard/common-util": "3.1.15",
46
- "@carecard/validate": "3.1.24"
45
+ "@carecard/common-util": "3.2.0",
46
+ "@carecard/validate": "3.3.0"
47
47
  }
48
48
  }
package/readme.md CHANGED
@@ -100,6 +100,19 @@ const urlSafe = stringUtilAuth.makeStringUrlSafe('a+b/c==');
100
100
  // Result: a-b_c
101
101
  ```
102
102
 
103
+ ## CareCard Auth Contract
104
+
105
+ `ms-auth` issues CareCard user JWTs and now enforces its own auth tables with
106
+ forced PostgreSQL RLS. This package should preserve JWT claim values exactly
107
+ when creating or verifying tokens; a payload containing `roles: ["ad"]` is the
108
+ auth-service super-admin signal. Do not add helpers that hide, rename, or drop
109
+ the `roles` array, and do not add database bypass behavior to this package.
110
+
111
+ Docs that mention `ms-auth` controller internals should use concise action
112
+ names such as `loginUser`, `registerUser`, `getUserDetail`, and `renewJwt`.
113
+ Access level is conveyed by route middleware and endpoint placement, not by
114
+ `public`/`protected`/`admin`/`Handler` suffixes.
115
+
103
116
  ## Testing
104
117
 
105
118
  Run tests using:
package/.prettierignore DELETED
@@ -1,17 +0,0 @@
1
- dist/
2
- coverage/
3
- node_modules/
4
- build/
5
- *.min.js
6
- .github
7
- .husky
8
- dist
9
- .gitignore
10
- .npmignore
11
- .prettierignore
12
- .prettierrc.js
13
- eslint.config.mjs
14
- jest.config.js
15
- package.json
16
- readme.md
17
- rename-cjs.js
package/.prettierrc.cjs DELETED
@@ -1,32 +0,0 @@
1
- /** @type {import('prettier').Config} */
2
- module.exports = {
3
- // Core formatting
4
- printWidth: 100,
5
- tabWidth: 2,
6
- useTabs: false,
7
- semi: true,
8
- singleQuote: true,
9
- trailingComma: 'all',
10
- bracketSpacing: true,
11
- bracketSameLine: true,
12
- arrowParens: 'avoid',
13
-
14
- // Line endings (important for cross-platform + CI)
15
- endOfLine: 'auto',
16
-
17
- // Language-specific overrides
18
- overrides: [
19
- {
20
- files: '*.json',
21
- options: {
22
- printWidth: 80,
23
- },
24
- },
25
- {
26
- files: '*.md',
27
- options: {
28
- proseWrap: 'preserve',
29
- },
30
- },
31
- ],
32
- };
package/jest.config.js DELETED
@@ -1,16 +0,0 @@
1
- export default {
2
- preset: 'ts-jest',
3
- testEnvironment: 'node',
4
- transform: {
5
- '^.+\\.ts$': [
6
- 'ts-jest',
7
- {
8
- tsconfig: 'tsconfig.base.json',
9
- },
10
- ],
11
- },
12
- testMatch: ['**/tests/**/*.test.ts'],
13
- collectCoverage: true,
14
- collectCoverageFrom: ['src/**/*.ts'],
15
- coverageDirectory: 'coverage'
16
- };
@@ -1,13 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
-
4
- const dir = './dist/cjs';
5
-
6
- for (const file of fs.readdirSync(dir)) {
7
- if (file.endsWith('.js')) {
8
- fs.renameSync(
9
- path.join(dir, file),
10
- path.join(dir, file.replace('.js', '.cjs'))
11
- );
12
- }
13
- }
@@ -1,111 +0,0 @@
1
- import * as crypto from 'crypto';
2
-
3
- /**
4
- * Signs a token returns signature string
5
- * @param token
6
- * @param privateKey
7
- * @param signingAlgorithm
8
- * @returns {string}
9
- */
10
- export const createBase64SignatureOfToken = function (
11
- token: string = '',
12
- privateKey: string,
13
- signingAlgorithm: string,
14
- ): string {
15
- const sign = crypto.createSign(signingAlgorithm);
16
- sign.write(token);
17
- sign.end();
18
- return sign.sign(privateKey, 'base64');
19
- };
20
-
21
- /**
22
- * Verifies the signature returns true or false
23
- * @param token
24
- * @param signature
25
- * @param publicKey
26
- * @param signingAlgorithm
27
- * @returns {boolean}
28
- */
29
- export const verifyBase64SignatureOfToken = function (
30
- token: string = '',
31
- signature: string,
32
- publicKey: string,
33
- signingAlgorithm: string,
34
- ): boolean {
35
- const verify = crypto.createVerify(signingAlgorithm);
36
- verify.update(token);
37
- verify.end();
38
- return verify.verify(publicKey, signature, 'base64');
39
- };
40
-
41
- /**
42
- * Creates the hash of given string
43
- * @param string
44
- * @param secret
45
- * @param algorithm
46
- * @returns {string}
47
- */
48
- export const createHmacBase64 = function (
49
- string: string = '',
50
- secret: string,
51
- algorithm: string,
52
- ): string {
53
- const hmac = crypto.createHmac(algorithm, secret);
54
- hmac.update(string);
55
- return hmac.digest('base64');
56
- };
57
-
58
- /**
59
- * Create random salt
60
- * @returns {string}
61
- */
62
- export const createSaltBase64 = (): string => {
63
- const date = new Date().valueOf();
64
- const hmac = crypto.createHmac('SHA256', date.toString());
65
- hmac.update(date.toString());
66
- return hmac.digest('base64');
67
- };
68
-
69
- /**
70
- * Encrypt given string
71
- * @param string
72
- * @param salt
73
- * @param secret
74
- * @param algorithm
75
- * @returns {string}
76
- */
77
- export const encryptStringAsciiToBase64 = (
78
- string: string,
79
- salt: string,
80
- secret: string,
81
- algorithm: string,
82
- ): string => {
83
- const key = crypto.scryptSync(secret, salt, 24);
84
- const iv = Buffer.alloc(16, 0);
85
- const cipher = crypto.createCipheriv(algorithm, key, iv);
86
- let encrypted = cipher.update(string, 'ascii', 'base64');
87
- encrypted += cipher.final('base64');
88
- return encrypted;
89
- };
90
-
91
- /**
92
- * Decrypts given string
93
- * @param encryptedString
94
- * @param salt
95
- * @param secret
96
- * @param algorithm
97
- * @returns {string}
98
- */
99
- export const decryptStringBase64ToAscii = (
100
- encryptedString: string,
101
- salt: string,
102
- secret: string,
103
- algorithm: string,
104
- ): string => {
105
- const key = crypto.scryptSync(secret, salt, 24);
106
- const iv = Buffer.alloc(16, 0);
107
- const decipher = crypto.createDecipheriv(algorithm, key, iv);
108
- let decrypted = decipher.update(encryptedString, 'base64', 'ascii');
109
- decrypted += decipher.final('ascii');
110
- return decrypted;
111
- };
package/src/index.ts DELETED
@@ -1,6 +0,0 @@
1
- export * from './cryptoUtilAuth';
2
- export * from './jwtUtilAuth';
3
- export * from './keyGen';
4
- export * from './pwdUtilAuth';
5
- export * from './strEncryptUtil';
6
- export * from './stringUtilAuth';
@@ -1,85 +0,0 @@
1
- import * as stringUtilAuth from './stringUtilAuth';
2
- import * as cryptoUtilAuth from './cryptoUtilAuth';
3
-
4
- /**
5
- * User supplied header, payload and signature create jwt.
6
- * @returns {string|null}
7
- * @param headerBase64
8
- * @param payloadBase64
9
- * @param signatureBase64
10
- */
11
- export const _assembleJwt = (
12
- headerBase64: string,
13
- payloadBase64: string,
14
- signatureBase64: string,
15
- ): string => {
16
- return headerBase64 + '.' + payloadBase64 + '.' + signatureBase64;
17
- };
18
-
19
- /**
20
- * User supplied header, payload and signature create jwt.
21
- * @returns {{payload: *, signature: *, header: *}}
22
- * @param jwt
23
- */
24
- export const _splitJwtInToHeaderPayloadSignature = (jwt: string): any => {
25
- return stringUtilAuth.dotConnectedStringToHeaderPayloadSignature(jwt);
26
- };
27
-
28
- /**
29
- * Creates Url safe jwt
30
- * @param headerObject
31
- * @param payloadObject
32
- * @param privateKey
33
- * @return {string|null}
34
- */
35
- export const createSignedJwtFromObject = (
36
- headerObject: any,
37
- payloadObject: any,
38
- privateKey: string,
39
- ): any => {
40
- try {
41
- const algorithm = headerObject.alg;
42
- const headerBase64UrlSafe = stringUtilAuth.objectToBase64UrlSafeString(headerObject);
43
- const payloadBase64UrlSafe = stringUtilAuth.objectToBase64UrlSafeString(payloadObject);
44
- const token = headerBase64UrlSafe + '.' + payloadBase64UrlSafe;
45
- const signature = cryptoUtilAuth.createBase64SignatureOfToken(token, privateKey, algorithm);
46
- const urlSafeSignature = stringUtilAuth.makeStringUrlSafe(signature);
47
- return _assembleJwt(headerBase64UrlSafe, payloadBase64UrlSafe, urlSafeSignature);
48
- } catch (error) {
49
- return null;
50
- }
51
- };
52
-
53
- /**
54
- * Verify signature of jwt
55
- * @param jwt
56
- * @param publicKey
57
- * @return {boolean}
58
- */
59
- export const verifyJwtSignature = (jwt: string, publicKey: string): boolean => {
60
- try {
61
- const { header, payload, signature } = _splitJwtInToHeaderPayloadSignature(jwt);
62
- const token = header + '.' + payload;
63
- const headerObject = stringUtilAuth.urlSafeBase64ToObject(header);
64
- return cryptoUtilAuth.verifyBase64SignatureOfToken(
65
- token,
66
- signature,
67
- publicKey,
68
- headerObject.alg,
69
- );
70
- } catch (error) {
71
- return false;
72
- }
73
- };
74
-
75
- /**
76
- * Returns header and payload object for jwt.
77
- * @param jwt
78
- * @return {{payload: any, header: any}}
79
- */
80
- export const getHeaderPayloadFromJwt = (jwt: string): any => {
81
- const { header, payload } = _splitJwtInToHeaderPayloadSignature(jwt);
82
- let headerAscii = stringUtilAuth.base64ToAscii(header);
83
- let payloadAscii = stringUtilAuth.base64ToAscii(payload);
84
- return { header: JSON.parse(headerAscii), payload: JSON.parse(payloadAscii) };
85
- };
package/src/keyGen.ts DELETED
@@ -1,14 +0,0 @@
1
- import { generateKeyPairSync } from 'node:crypto';
2
-
3
- export const generateKeyPair = (modulusLength: number = 4096) =>
4
- generateKeyPairSync('rsa', {
5
- modulusLength: modulusLength,
6
- publicKeyEncoding: {
7
- type: 'spki',
8
- format: 'pem',
9
- },
10
- privateKeyEncoding: {
11
- type: 'pkcs8',
12
- format: 'pem',
13
- },
14
- });
@@ -1,78 +0,0 @@
1
- import * as cryptoUtilAuth from './cryptoUtilAuth';
2
- import * as stringUtilAuth from './stringUtilAuth';
3
-
4
- /**
5
- * Just assemble password together
6
- * @param algorithmBase64
7
- * @param hashBase64
8
- * @param saltBase64
9
- * @return {string}
10
- */
11
- export const _assemblePasswordHash = (
12
- algorithmBase64: string,
13
- hashBase64: string,
14
- saltBase64: string,
15
- ): string => {
16
- return '$1$' + algorithmBase64 + '$' + hashBase64 + '$' + saltBase64 + '$';
17
- };
18
-
19
- /**
20
- * Break password into its parts does not reverse base64 encoding.
21
- * @param passwordHashStored
22
- * @return {{salt: *, version: *, alg: *, hash: *}}
23
- */
24
- export const _disassemblePasswordHash = (passwordHashStored: string): any => {
25
- return stringUtilAuth.dollarSignConnectedStringToAlgorithmHashSalt(passwordHashStored);
26
- };
27
-
28
- /**
29
- * Creates password hash ready to be saved in database.
30
- * @param password
31
- * @param secret
32
- * @param salt
33
- * @param algorithm
34
- * @return {string}
35
- */
36
- export const _createPasswordHash = (
37
- password: string,
38
- secret: string,
39
- salt: string,
40
- algorithm: string,
41
- ): string => {
42
- const algorithmBase64 = stringUtilAuth.asciiToBase64(algorithm);
43
- const hashBase64 = cryptoUtilAuth.createHmacBase64(password, secret, algorithm);
44
- return _assemblePasswordHash(algorithmBase64, hashBase64, salt);
45
- };
46
-
47
- /**
48
- * Automatically adds random salt.
49
- * @param password
50
- * @param secret
51
- * @param algorithm
52
- * @return {string}
53
- */
54
- export const createPasswordHashWithRandomSalt = (
55
- password: string,
56
- secret: string,
57
- algorithm: string,
58
- ): string => {
59
- const salt = cryptoUtilAuth.createSaltBase64();
60
- return _createPasswordHash(password, secret, salt, algorithm);
61
- };
62
-
63
- /**
64
- * Creates hash based on saved hash in database.
65
- * @param password
66
- * @param savedPasswordHash
67
- * @param secret
68
- * @return {string}
69
- */
70
- export const createPasswordHashBasedOnSavedAlgorithmSalt = (
71
- password: string,
72
- savedPasswordHash: string,
73
- secret: string,
74
- ): string => {
75
- const { alg, salt } = _disassemblePasswordHash(savedPasswordHash);
76
- const algorithm = stringUtilAuth.base64ToAscii(alg);
77
- return _createPasswordHash(password, secret, salt, algorithm);
78
- };