@cocreate/authenticate 1.10.2 → 1.12.1
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/.github/workflows/automated.yml +25 -38
- package/CHANGELOG.md +28 -0
- package/package.json +4 -12
- package/release.config.js +12 -4
- package/src/index.js +145 -111
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
name: Automated Workflow
|
|
2
|
+
|
|
2
3
|
on:
|
|
3
4
|
push:
|
|
4
5
|
branches:
|
|
5
6
|
- master
|
|
7
|
+
|
|
6
8
|
jobs:
|
|
7
9
|
about:
|
|
8
10
|
runs-on: ubuntu-latest
|
|
@@ -18,52 +20,37 @@ jobs:
|
|
|
18
20
|
with:
|
|
19
21
|
direction: overwrite-github
|
|
20
22
|
githubToken: "${{ secrets.GITHUB }}"
|
|
23
|
+
|
|
21
24
|
release:
|
|
22
25
|
runs-on: ubuntu-latest
|
|
23
26
|
steps:
|
|
24
27
|
- name: Checkout
|
|
25
|
-
uses: actions/checkout@
|
|
26
|
-
- name: Setup Node.js
|
|
27
|
-
uses: actions/setup-node@v3
|
|
28
|
+
uses: actions/checkout@v4
|
|
28
29
|
with:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
fetch-depth: 0 # Required so semantic-release can trace git tags/history
|
|
31
|
+
|
|
32
|
+
- name: Setup Node.js
|
|
33
|
+
uses: actions/setup-node@v4
|
|
33
34
|
with:
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
node-version: 22
|
|
36
|
+
|
|
37
|
+
- name: Install Semantic Release & Plugins
|
|
38
|
+
# Installs semantic-release and its plugins on the runner
|
|
39
|
+
run: |
|
|
40
|
+
npm install -g semantic-release \
|
|
41
|
+
@semantic-release/changelog \
|
|
42
|
+
@semantic-release/npm \
|
|
43
|
+
@semantic-release/github \
|
|
36
44
|
@semantic-release/git
|
|
37
|
-
|
|
45
|
+
|
|
46
|
+
- name: Run Semantic Release (Native)
|
|
47
|
+
id: semantic
|
|
48
|
+
# This will automatically pick up your export default config file in the repository root
|
|
49
|
+
run: npx semantic-release
|
|
38
50
|
env:
|
|
39
|
-
GITHUB_TOKEN: "${{ secrets.
|
|
51
|
+
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
|
40
52
|
NPM_TOKEN: "${{ secrets.NPM_TOKEN }}"
|
|
53
|
+
|
|
41
54
|
outputs:
|
|
42
55
|
new_release_published: "${{ steps.semantic.outputs.new_release_published }}"
|
|
43
|
-
new_release_version: "${{ steps.semantic.outputs.new_release_version }}"
|
|
44
|
-
upload:
|
|
45
|
-
runs-on: ubuntu-latest
|
|
46
|
-
needs: release
|
|
47
|
-
if: needs.release.outputs.new_release_published == 'true'
|
|
48
|
-
env:
|
|
49
|
-
VERSION: "${{ needs.release.outputs.new_release_version }}"
|
|
50
|
-
steps:
|
|
51
|
-
- name: Checkout
|
|
52
|
-
uses: actions/checkout@v3
|
|
53
|
-
- name: Setup Node.js
|
|
54
|
-
uses: actions/setup-node@v3
|
|
55
|
-
with:
|
|
56
|
-
node-version: 16
|
|
57
|
-
- name: Set npm registry auth
|
|
58
|
-
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
|
|
59
|
-
- name: Install dependencies
|
|
60
|
-
run: yarn install
|
|
61
|
-
|
|
62
|
-
- name: Set Environment Variables
|
|
63
|
-
run: |
|
|
64
|
-
echo "organization_id=${{ secrets.COCREATE_ORGANIZATION_ID }}" >> $GITHUB_ENV
|
|
65
|
-
echo "key=${{ secrets.COCREATE_KEY }}" >> $GITHUB_ENV
|
|
66
|
-
echo "host=${{ secrets.COCREATE_HOST }}" >> $GITHUB_ENV
|
|
67
|
-
- name: CoCreate Upload
|
|
68
|
-
run: coc upload
|
|
69
|
-
|
|
56
|
+
new_release_version: "${{ steps.semantic.outputs.new_release_version }}"
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
## [1.12.1](https://github.com/CoCreate-app/CoCreate-authenticate/compare/v1.12.0...v1.12.1) (2026-07-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* bump dependencies ([45aac1d](https://github.com/CoCreate-app/CoCreate-authenticate/commit/45aac1d37a9afb021ff4fb2556d41fa608769f1b))
|
|
7
|
+
|
|
8
|
+
# [1.12.0](https://github.com/CoCreate-app/CoCreate-authenticate/compare/v1.11.0...v1.12.0) (2026-07-17)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* update automated workflow and release configuration for improved semantic release handling ([27e796c](https://github.com/CoCreate-app/CoCreate-authenticate/commit/27e796c89a53e9efeb708e736ef003b16aa5df9e))
|
|
14
|
+
|
|
15
|
+
# [1.11.0](https://github.com/CoCreate-app/CoCreate-authenticate/compare/v1.10.2...v1.11.0) (2026-07-14)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* removed post install ([5fd376c](https://github.com/CoCreate-app/CoCreate-authenticate/commit/5fd376cdfe83f0902c3e34c962ac7b45713a6bea))
|
|
21
|
+
* semantic version handling. Reorganize .gitignore for improved clarity and structure ([142646c](https://github.com/CoCreate-app/CoCreate-authenticate/commit/142646cf3d25491af4113c98f51361a71be72193))
|
|
22
|
+
* update module export to ES6 syntax in release.config.js ([ed8bcac](https://github.com/CoCreate-app/CoCreate-authenticate/commit/ed8bcac530a19268a9259babcf4cd975c301b1cd))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* add ESM support and improve key pair management functions ([2418adb](https://github.com/CoCreate-app/CoCreate-authenticate/commit/2418adba54911236be478783b3b965e4cfcf9e98))
|
|
28
|
+
|
|
1
29
|
## [1.10.2](https://github.com/CoCreate-app/CoCreate-authenticate/compare/v1.10.1...v1.10.2) (2025-05-01)
|
|
2
30
|
|
|
3
31
|
|
package/package.json
CHANGED
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cocreate/authenticate",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"description": "A simple authenticate component in vanilla javascript. Easily configured using HTML5 data-attributes and/or JavaScript API.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authenticate",
|
|
7
|
-
"cocreate",
|
|
8
|
-
"low-code-framework",
|
|
9
|
-
"no-code-framework",
|
|
10
|
-
"cocreatejs",
|
|
11
|
-
"cocreatejs-component",
|
|
12
|
-
"cocreate-framework",
|
|
13
|
-
"no-code",
|
|
14
7
|
"low-code",
|
|
15
|
-
"collaborative-framework",
|
|
16
8
|
"realtime",
|
|
17
9
|
"realtime-framework",
|
|
18
10
|
"collaboration",
|
|
@@ -21,9 +13,8 @@
|
|
|
21
13
|
"javascript-framework"
|
|
22
14
|
],
|
|
23
15
|
"scripts": {
|
|
24
|
-
"start": "
|
|
25
|
-
"build": "NODE_ENV=production
|
|
26
|
-
"postinstall": "node -e \"const { execSync } = require('child_process'); try { execSync('coc --version', { stdio: 'ignore' }); } catch (error) { try { execSync('npm install -g @cocreate/cli', { stdio: 'inherit' }); console.log('Installed \"@cocreate/cli\" globally.'); } catch (error) { console.error('Failed to install \"@cocreate/cli\" globally:', error); } }\""
|
|
16
|
+
"start": "webpack --config webpack.config.js --watch",
|
|
17
|
+
"build": "NODE_ENV=production webpack --config webpack.config.js"
|
|
27
18
|
},
|
|
28
19
|
"publishConfig": {
|
|
29
20
|
"access": "public"
|
|
@@ -37,6 +28,7 @@
|
|
|
37
28
|
"bugs": {
|
|
38
29
|
"url": "https://github.com/CoCreate-app/CoCreate-authenticate/issues"
|
|
39
30
|
},
|
|
31
|
+
"type": "module",
|
|
40
32
|
"main": "./src/index.js",
|
|
41
33
|
"homepage": "https://cocreate.app/docs/authenticate",
|
|
42
34
|
"dependencies": {
|
package/release.config.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
export default {
|
|
2
2
|
dryRun: false,
|
|
3
3
|
branches: ["master"],
|
|
4
4
|
plugins: [
|
|
@@ -10,12 +10,20 @@ module.exports = {
|
|
|
10
10
|
changelogFile: "CHANGELOG.md",
|
|
11
11
|
},
|
|
12
12
|
],
|
|
13
|
-
"@semantic-release/npm",
|
|
14
|
-
"@semantic-release/github",
|
|
13
|
+
"@semantic-release/npm",
|
|
15
14
|
[
|
|
16
|
-
"@semantic-release/
|
|
15
|
+
"@semantic-release/github",
|
|
17
16
|
{
|
|
17
|
+
successComment: false,
|
|
18
|
+
failTitle: false,
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
"@semantic-release/git",
|
|
23
|
+
{
|
|
24
|
+
// Only stage and commit the changelog and package.json
|
|
18
25
|
assets: ["CHANGELOG.md", "package.json"],
|
|
26
|
+
message: "chore(release): ${nextRelease.version} [skip ci]",
|
|
19
27
|
},
|
|
20
28
|
],
|
|
21
29
|
],
|
package/src/index.js
CHANGED
|
@@ -1,86 +1,104 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (C) 2023 CoCreate and Contributors.
|
|
3
|
+
*
|
|
4
|
+
* This program is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU Affero General Public License as published
|
|
6
|
+
* by the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
* (at your option) any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU Affero General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
********************************************************************************/
|
|
17
|
+
|
|
18
|
+
// Commercial Licensing Information:
|
|
19
|
+
// For commercial use of this software without the copyleft provisions of the AGPLv3,
|
|
20
|
+
// you must obtain a commercial license from CoCreate LLC.
|
|
21
|
+
// For details, visit <https://cocreate.app/licenses/> or contact us at sales@cocreate.app.
|
|
22
|
+
|
|
23
|
+
import crypto from 'crypto';
|
|
24
|
+
import jwt from 'jsonwebtoken';
|
|
25
|
+
import crud from '@cocreate/crud-server';
|
|
26
|
+
|
|
27
|
+
// ==========================================
|
|
28
|
+
// Module-Level Sandbox State (ESM Singleton Container)
|
|
29
|
+
// ==========================================
|
|
5
30
|
const tokenExpiration = 60; // Token expiration in minutes
|
|
6
|
-
|
|
7
|
-
// Array to store key pairs
|
|
8
31
|
const keyPairs = new Map();
|
|
9
|
-
|
|
10
|
-
// Map to store authenticated user payload and tokens
|
|
11
32
|
const sessions = new Map();
|
|
12
33
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
// crud.send({
|
|
36
|
-
// method: 'object.create',
|
|
37
|
-
// array: 'keys',
|
|
38
|
-
// object: {
|
|
39
|
-
// ...keyPair,
|
|
40
|
-
// },
|
|
41
|
-
// organization_id: process.env.organization_id,
|
|
42
|
-
// });
|
|
43
|
-
|
|
44
|
-
return keyPair;
|
|
45
|
-
}
|
|
34
|
+
/**
|
|
35
|
+
* Generates a new RSA key pair dynamically and tracks its expiration lifecycle.
|
|
36
|
+
* @returns {Object} Newly created key pair configuration
|
|
37
|
+
*/
|
|
38
|
+
function createKeyPair() {
|
|
39
|
+
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
|
|
40
|
+
modulusLength: 2048,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const created = new Date(new Date().toISOString()).getTime();
|
|
44
|
+
const keyPair = {
|
|
45
|
+
_id: crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).substring(2),
|
|
46
|
+
privateKey,
|
|
47
|
+
publicKey,
|
|
48
|
+
created,
|
|
49
|
+
expires: created + tokenExpiration * 60 * 1000,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
keyPairs.set(keyPair._id, keyPair);
|
|
53
|
+
return keyPair;
|
|
54
|
+
}
|
|
46
55
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// _id: keyPair._id,
|
|
55
|
-
// type: 'RSA'
|
|
56
|
-
// },
|
|
57
|
-
// organization_id: process.env.organization_id,
|
|
58
|
-
// });
|
|
56
|
+
/**
|
|
57
|
+
* Deletes an expired or revoked RSA key pair from local tracking.
|
|
58
|
+
* @param {Object} keyPair - The target key pair to remove
|
|
59
|
+
*/
|
|
60
|
+
function deleteKeyPair(keyPair) {
|
|
61
|
+
if (keyPair && keyPair._id) {
|
|
62
|
+
keyPairs.delete(keyPair._id);
|
|
59
63
|
}
|
|
64
|
+
}
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
keyPair = this.createKeyPair();
|
|
66
|
+
/**
|
|
67
|
+
* Creates and signs a new token utilizing the latest available RSA key pair.
|
|
68
|
+
* Saves session markers back to storage and registers client tracking nodes.
|
|
69
|
+
*/
|
|
70
|
+
function encodeToken(organization_id, user_id, clientId, host) {
|
|
71
|
+
let keyPair = null;
|
|
72
|
+
const currentTime = new Date(new Date().toISOString()).getTime();
|
|
73
|
+
|
|
74
|
+
for (let [key, value] of keyPairs) {
|
|
75
|
+
if (currentTime > value.expires) {
|
|
76
|
+
deleteKeyPair(value);
|
|
77
|
+
} else {
|
|
78
|
+
keyPair = value;
|
|
75
79
|
}
|
|
80
|
+
}
|
|
76
81
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const session = { user_id, clientId, token, expires: currentTime + tokenExpiration * 60 * 1000 }
|
|
81
|
-
sessions.set(clientId, session)
|
|
82
|
+
if (!keyPair) {
|
|
83
|
+
keyPair = createKeyPair();
|
|
84
|
+
}
|
|
82
85
|
|
|
83
|
-
|
|
86
|
+
const token = jwt.sign({ user_id, clientId }, keyPair.privateKey, {
|
|
87
|
+
algorithm: 'RS256',
|
|
88
|
+
expiresIn: tokenExpiration * 60
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const session = {
|
|
92
|
+
user_id,
|
|
93
|
+
clientId,
|
|
94
|
+
token,
|
|
95
|
+
expires: currentTime + tokenExpiration * 60 * 1000
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
sessions.set(clientId, session);
|
|
99
|
+
|
|
100
|
+
if (crud) {
|
|
101
|
+
crud.send({
|
|
84
102
|
method: 'object.update',
|
|
85
103
|
host,
|
|
86
104
|
array: 'clients',
|
|
@@ -91,58 +109,74 @@ class CoCreateAuthenticate {
|
|
|
91
109
|
upsert: true,
|
|
92
110
|
organization_id
|
|
93
111
|
});
|
|
94
|
-
|
|
95
|
-
return token;
|
|
96
112
|
}
|
|
97
113
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (!token)
|
|
101
|
-
return {}
|
|
102
|
-
const currentTime = new Date().getTime();
|
|
103
|
-
|
|
104
|
-
let session = sessions.get(clientId)
|
|
105
|
-
if (!session || session.token !== token)
|
|
106
|
-
session = await this.read(organization_id, clientId, host)
|
|
107
|
-
|
|
108
|
-
// TODO: request must be made from same clientId and user_id that created the token
|
|
109
|
-
if (session && currentTime < session.expires && session.token === token)
|
|
110
|
-
return { user_id: session.user_id, expires: session.expires };
|
|
114
|
+
return token;
|
|
115
|
+
}
|
|
111
116
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Reads, parses, and validates the configuration and active state of client sessions.
|
|
119
|
+
*/
|
|
120
|
+
async function read(organization_id, clientId, host) {
|
|
121
|
+
if (!crud) return null;
|
|
122
|
+
|
|
123
|
+
const client = await crud.send({
|
|
124
|
+
method: 'object.read',
|
|
125
|
+
host,
|
|
126
|
+
array: 'clients',
|
|
127
|
+
object: {
|
|
128
|
+
_id: clientId
|
|
129
|
+
},
|
|
130
|
+
organization_id,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (client && client.object && client.object.length) {
|
|
134
|
+
sessions.set(clientId, client.object[0].session);
|
|
135
|
+
return client.object[0].session;
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
123
139
|
|
|
124
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Verifies and decodes an incoming session token, resolving the associated user identifier.
|
|
142
|
+
*/
|
|
143
|
+
async function decodeToken(token, organization_id, clientId, host) {
|
|
144
|
+
if (!token) return {};
|
|
145
|
+
|
|
146
|
+
const currentTime = new Date().getTime();
|
|
147
|
+
let session = sessions.get(clientId);
|
|
148
|
+
|
|
149
|
+
if (!session || session.token !== token) {
|
|
150
|
+
session = await read(organization_id, clientId, host);
|
|
151
|
+
}
|
|
125
152
|
|
|
153
|
+
if (session && currentTime < session.expires && session.token === token) {
|
|
154
|
+
return { user_id: session.user_id, expires: session.expires };
|
|
126
155
|
}
|
|
127
156
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
157
|
+
sessions.delete(clientId);
|
|
158
|
+
|
|
159
|
+
if (crud) {
|
|
160
|
+
crud.send({
|
|
161
|
+
method: 'object.update',
|
|
131
162
|
host,
|
|
132
163
|
array: 'clients',
|
|
133
164
|
object: {
|
|
134
|
-
_id: clientId
|
|
165
|
+
_id: clientId,
|
|
166
|
+
session: null
|
|
135
167
|
},
|
|
136
168
|
organization_id,
|
|
137
169
|
});
|
|
138
|
-
|
|
139
|
-
if (client.object && client.object.length) {
|
|
140
|
-
sessions.set(clientId, client.object[0].session)
|
|
141
|
-
return client.object[0].session
|
|
142
|
-
}
|
|
143
|
-
|
|
144
170
|
}
|
|
145
171
|
|
|
172
|
+
return {};
|
|
146
173
|
}
|
|
147
174
|
|
|
148
|
-
|
|
175
|
+
// Export the API directly as a flat default object manifest
|
|
176
|
+
export default {
|
|
177
|
+
createKeyPair,
|
|
178
|
+
deleteKeyPair,
|
|
179
|
+
encodeToken,
|
|
180
|
+
decodeToken,
|
|
181
|
+
read
|
|
182
|
+
};
|