stigmergy 1.2.6 → 1.2.8
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/README.md +32 -17
- package/STIGMERGY.md +16 -7
- package/docs/MULTI_USER_WIKI_COLLABORATION_SYSTEM.md +523 -0
- package/docs/PROMPT_BASED_SKILLS_SYSTEM_DESIGN.md +458 -0
- package/docs/SKILL_IMPLEMENTATION_CONSTRAINTS_AND_ALIGNMENT.md +423 -0
- package/docs/TECHNICAL_FEASIBILITY_ANALYSIS.md +308 -0
- package/examples/multilingual-hook-demo.js +125 -0
- package/package.json +14 -17
- package/scripts/dependency-analyzer.js +101 -0
- package/scripts/generate-cli-docs.js +64 -0
- package/scripts/postuninstall.js +46 -0
- package/scripts/preuninstall.js +75 -0
- package/scripts/run-layered-tests.js +3 -3
- package/src/adapters/claude/install_claude_integration.js +17 -17
- package/src/adapters/codebuddy/install_codebuddy_integration.js +13 -13
- package/src/adapters/codex/install_codex_integration.js +27 -27
- package/src/adapters/copilot/install_copilot_integration.js +46 -46
- package/src/adapters/gemini/install_gemini_integration.js +10 -10
- package/src/adapters/iflow/install_iflow_integration.js +7 -7
- package/src/adapters/qoder/install_qoder_integration.js +12 -12
- package/src/adapters/qwen/install_qwen_integration.js +17 -17
- package/src/auth.js +173 -173
- package/src/auth_command.js +208 -208
- package/src/calculator.js +313 -313
- package/src/cli/router.js +151 -7
- package/src/core/cache_cleaner.js +767 -767
- package/src/core/cli_help_analyzer.js +680 -680
- package/src/core/cli_parameter_handler.js +132 -132
- package/src/core/cli_tools.js +89 -89
- package/src/core/coordination/index.js +16 -16
- package/src/core/coordination/nodejs/AdapterManager.js +102 -102
- package/src/core/coordination/nodejs/CLCommunication.js +132 -132
- package/src/core/coordination/nodejs/CLIIntegrationManager.js +272 -272
- package/src/core/coordination/nodejs/HealthChecker.js +76 -76
- package/src/core/coordination/nodejs/HookDeploymentManager.js +463 -274
- package/src/core/coordination/nodejs/StatisticsCollector.js +71 -71
- package/src/core/coordination/nodejs/index.js +90 -90
- package/src/core/coordination/nodejs/utils/Logger.js +29 -29
- package/src/core/enhanced_installer.js +479 -479
- package/src/core/enhanced_uninstaller.js +638 -638
- package/src/core/error_handler.js +406 -406
- package/src/core/installer.js +32 -32
- package/src/core/memory_manager.js +83 -83
- package/src/core/multilingual/language-pattern-manager.js +172 -0
- package/src/core/rest_client.js +160 -160
- package/src/core/smart_router.js +261 -249
- package/src/core/upgrade_manager.js +48 -20
- package/src/data_encryption.js +143 -143
- package/src/data_structures.js +440 -440
- package/src/deploy.js +55 -55
- package/src/index.js +30 -30
- package/src/test/cli-availability-checker.js +194 -194
- package/src/test/test-environment.js +289 -289
- package/src/utils/helpers.js +35 -35
- package/src/utils.js +921 -921
- package/src/weatherProcessor.js +228 -228
- package/test/multilingual/hook-deployment.test.js +91 -0
- package/test/multilingual/language-pattern-manager.test.js +140 -0
- package/test/multilingual/system-test.js +85 -0
|
@@ -219,7 +219,7 @@ class QoderHookInstaller {
|
|
|
219
219
|
cross_cli: true
|
|
220
220
|
},
|
|
221
221
|
keywords: {
|
|
222
|
-
cross_cli: [
|
|
222
|
+
cross_cli: ['请用', '调用', '用', '让', 'use', 'call', 'ask']
|
|
223
223
|
}
|
|
224
224
|
};
|
|
225
225
|
await fs.writeFile(configDest, JSON.stringify(defaultConfig, null, 2));
|
|
@@ -264,7 +264,7 @@ class QoderHookInstaller {
|
|
|
264
264
|
|
|
265
265
|
COMMAND="$1"
|
|
266
266
|
STAGE="pre_command"
|
|
267
|
-
SESSION_ID="
|
|
267
|
+
SESSION_ID="\${QODER_HOOK_SESSION_ID:-$(date +%s)}"
|
|
268
268
|
|
|
269
269
|
# 设置环境变量
|
|
270
270
|
export QODER_HOOK_STAGE="$STAGE"
|
|
@@ -317,7 +317,7 @@ exit 0
|
|
|
317
317
|
EXIT_CODE=$?
|
|
318
318
|
STAGE="post_command"
|
|
319
319
|
COMMAND="$1"
|
|
320
|
-
SESSION_ID="
|
|
320
|
+
SESSION_ID="\${QODER_HOOK_SESSION_ID:-$(date +%s)}"
|
|
321
321
|
|
|
322
322
|
# 设置环境变量
|
|
323
323
|
export QODER_HOOK_STAGE="$STAGE"
|
|
@@ -369,7 +369,7 @@ exit $EXIT_CODE
|
|
|
369
369
|
EXIT_CODE=$?
|
|
370
370
|
STAGE="error_handling"
|
|
371
371
|
COMMAND="$1"
|
|
372
|
-
SESSION_ID="
|
|
372
|
+
SESSION_ID="\${QODER_HOOK_SESSION_ID:-$(date +%s)}"
|
|
373
373
|
|
|
374
374
|
# 设置环境变量
|
|
375
375
|
export QODER_HOOK_STAGE="$STAGE"
|
|
@@ -527,14 +527,14 @@ exit /b 0
|
|
|
527
527
|
async _setupEnvironmentConfig() {
|
|
528
528
|
try {
|
|
529
529
|
const envConfig = {
|
|
530
|
-
QODER_CROSS_CLI_ENABLED:
|
|
531
|
-
QODER_CROSS_CLI_RESPONSE_FILE:
|
|
532
|
-
QODER_CROSS_CLI_REQUEST_FILE:
|
|
533
|
-
QODER_CROSS_CLI_STATUS_FILE:
|
|
534
|
-
QODER_HOOK_STAGE:
|
|
535
|
-
QODER_HOOK_COMMAND:
|
|
536
|
-
QODER_HOOK_SESSION_ID:
|
|
537
|
-
QODER_HOOK_LOG_LEVEL:
|
|
530
|
+
QODER_CROSS_CLI_ENABLED: '1',
|
|
531
|
+
QODER_CROSS_CLI_RESPONSE_FILE: '',
|
|
532
|
+
QODER_CROSS_CLI_REQUEST_FILE: '',
|
|
533
|
+
QODER_CROSS_CLI_STATUS_FILE: '',
|
|
534
|
+
QODER_HOOK_STAGE: '',
|
|
535
|
+
QODER_HOOK_COMMAND: '',
|
|
536
|
+
QODER_HOOK_SESSION_ID: '',
|
|
537
|
+
QODER_HOOK_LOG_LEVEL: 'INFO',
|
|
538
538
|
QODER_HOOK_PLATFORM: os.platform()
|
|
539
539
|
};
|
|
540
540
|
|
|
@@ -41,10 +41,10 @@ class QwenInstaller {
|
|
|
41
41
|
// Define cross-CLI integration config
|
|
42
42
|
const crossCliConfig = {
|
|
43
43
|
cross_cli_enabled: true,
|
|
44
|
-
supported_clis: [
|
|
44
|
+
supported_clis: ['claude', 'gemini', 'qwen', 'iflow', 'qodercli', 'codebuddy', 'copilot', 'codex'],
|
|
45
45
|
auto_detect: true,
|
|
46
46
|
timeout: 30,
|
|
47
|
-
collaboration_mode:
|
|
47
|
+
collaboration_mode: 'active',
|
|
48
48
|
qwen_oauth_integration: true
|
|
49
49
|
};
|
|
50
50
|
|
|
@@ -72,12 +72,12 @@ class QwenInstaller {
|
|
|
72
72
|
const crossCliHooks = {
|
|
73
73
|
cross_cli_adapter: {
|
|
74
74
|
enabled: true,
|
|
75
|
-
supported_tools: [
|
|
75
|
+
supported_tools: ['claude', 'gemini', 'qwen', 'iflow', 'qodercli', 'codebuddy', 'copilot', 'codex'],
|
|
76
76
|
trigger_patterns: [
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
'use\\s+(\\w+)\\s+to\\s+(.+)$',
|
|
78
|
+
'call\\s+(\\w+)\\s+(.+)$',
|
|
79
|
+
'ask\\s+(\\w+)\\s+(.+)$',
|
|
80
|
+
'stigmergy\\s+(\\w+)\\s+(.+)$'
|
|
81
81
|
]
|
|
82
82
|
}
|
|
83
83
|
};
|
|
@@ -158,7 +158,7 @@ Examples:
|
|
|
158
158
|
Available tools: claude, gemini, qwen, iflow, qodercli, codebuddy, copilot, codex
|
|
159
159
|
`;
|
|
160
160
|
await fs.appendFile(qwenMdPath, crossCliContent);
|
|
161
|
-
console.log(
|
|
161
|
+
console.log('[OK] 在QWEN.md末尾追加Cross-CLI通信提示');
|
|
162
162
|
} catch (e) {
|
|
163
163
|
// File doesn't exist, that's ok
|
|
164
164
|
}
|
|
@@ -270,15 +270,15 @@ if (require.main === module) {
|
|
|
270
270
|
const command = args[0];
|
|
271
271
|
|
|
272
272
|
switch (command) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
273
|
+
case '--verify':
|
|
274
|
+
installer.verifyInstallation().then(success => process.exit(success ? 0 : 1));
|
|
275
|
+
break;
|
|
276
|
+
case '--uninstall':
|
|
277
|
+
installer.uninstallIntegration().then(success => process.exit(success ? 0 : 1));
|
|
278
|
+
break;
|
|
279
|
+
default:
|
|
280
|
+
installer.install().then(success => process.exit(success ? 0 : 1));
|
|
281
|
+
break;
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
|
package/src/auth.js
CHANGED
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Authentication module for the Stigmergy CLI system.
|
|
3
|
-
* Provides user authentication functionality including password hashing and token management.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const crypto = require('crypto');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Custom exception for authentication failures.
|
|
10
|
-
*/
|
|
11
|
-
class AuthenticationError extends Error {
|
|
12
|
-
constructor(message) {
|
|
13
|
-
super(message);
|
|
14
|
-
this.name = 'AuthenticationError';
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Handles user authentication operations including registration, login, and session management.
|
|
20
|
-
*/
|
|
21
|
-
class UserAuthenticator {
|
|
22
|
-
/**
|
|
23
|
-
* Create a new UserAuthenticator instance.
|
|
24
|
-
*/
|
|
25
|
-
constructor() {
|
|
26
|
-
// In production, this would be stored in a secure database
|
|
27
|
-
this._users = new Map();
|
|
28
|
-
this._sessions = new Map();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Register a new user with the provided username and password.
|
|
33
|
-
*
|
|
34
|
-
* @param {string} username - The user's username
|
|
35
|
-
* @param {string} password - The user's password
|
|
36
|
-
* @returns {boolean} True if registration successful, false if username already exists
|
|
37
|
-
* @throws {Error} If username or password is invalid
|
|
38
|
-
*/
|
|
39
|
-
registerUser(username, password) {
|
|
40
|
-
if (!username || !password) {
|
|
41
|
-
throw new Error('Username and password cannot be empty');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (username.length < 3) {
|
|
45
|
-
throw new Error('Username must be at least 3 characters long');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (password.length < 8) {
|
|
49
|
-
throw new Error('Password must be at least 8 characters long');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (this._users.has(username)) {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Hash the password with a salt
|
|
57
|
-
const salt = crypto.randomBytes(16).toString('hex');
|
|
58
|
-
const passwordHash = this._hashPassword(password, salt);
|
|
59
|
-
|
|
60
|
-
this._users.set(username, {
|
|
61
|
-
passwordHash: passwordHash,
|
|
62
|
-
salt: salt,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
return true;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Authenticate a user with the provided credentials.
|
|
70
|
-
*
|
|
71
|
-
* @param {string} username - The user's username
|
|
72
|
-
* @param {string} password - The user's password
|
|
73
|
-
* @returns {string} Session token if authentication is successful
|
|
74
|
-
* @throws {AuthenticationError} If authentication fails
|
|
75
|
-
*/
|
|
76
|
-
authenticateUser(username, password) {
|
|
77
|
-
if (!this._users.has(username)) {
|
|
78
|
-
throw new AuthenticationError('Invalid username or password');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const userData = this._users.get(username);
|
|
82
|
-
const passwordHash = this._hashPassword(password, userData.salt);
|
|
83
|
-
|
|
84
|
-
if (passwordHash !== userData.passwordHash) {
|
|
85
|
-
throw new AuthenticationError('Invalid username or password');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Generate session token
|
|
89
|
-
const sessionToken = crypto.randomBytes(32).toString('base64url');
|
|
90
|
-
this._sessions.set(sessionToken, {
|
|
91
|
-
username: username,
|
|
92
|
-
createdAt: Date.now(),
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
return sessionToken;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Validate a session token and return the associated username.
|
|
100
|
-
*
|
|
101
|
-
* @param {string} sessionToken - The session token to validate
|
|
102
|
-
* @returns {string|null} Username if session is valid, null otherwise
|
|
103
|
-
*/
|
|
104
|
-
validateSession(sessionToken) {
|
|
105
|
-
if (!this._sessions.has(sessionToken)) {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// In production, you would check session expiration here
|
|
110
|
-
return this._sessions.get(sessionToken).username;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Invalidate a session token.
|
|
115
|
-
*
|
|
116
|
-
* @param {string} sessionToken - The session token to invalidate
|
|
117
|
-
* @returns {boolean} True if session was invalidated, false if token was not found
|
|
118
|
-
*/
|
|
119
|
-
logout(sessionToken) {
|
|
120
|
-
if (this._sessions.has(sessionToken)) {
|
|
121
|
-
this._sessions.delete(sessionToken);
|
|
122
|
-
return true;
|
|
123
|
-
}
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Hash a password with the provided salt using PBKDF2.
|
|
129
|
-
*
|
|
130
|
-
* @param {string} password - The password to hash
|
|
131
|
-
* @param {string} salt - The salt to use for hashing
|
|
132
|
-
* @returns {string} The hashed password
|
|
133
|
-
* @private
|
|
134
|
-
*/
|
|
135
|
-
_hashPassword(password, salt) {
|
|
136
|
-
return crypto
|
|
137
|
-
.pbkdf2Sync(
|
|
138
|
-
password,
|
|
139
|
-
salt,
|
|
140
|
-
100000, // iterations
|
|
141
|
-
32, // key length
|
|
142
|
-
'sha256', // digest
|
|
143
|
-
)
|
|
144
|
-
.toString('hex');
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Helper function to authenticate a user and return a session token.
|
|
150
|
-
*
|
|
151
|
-
* @param {UserAuthenticator} authenticator - The authenticator instance
|
|
152
|
-
* @param {string} username - The user's username
|
|
153
|
-
* @param {string} password - The user's password
|
|
154
|
-
* @returns {[boolean, string]} A tuple containing success status and message/token
|
|
155
|
-
*/
|
|
156
|
-
function authenticateAndGetToken(authenticator, username, password) {
|
|
157
|
-
try {
|
|
158
|
-
const token = authenticator.authenticateUser(username, password);
|
|
159
|
-
return [true, token];
|
|
160
|
-
} catch (error) {
|
|
161
|
-
if (error instanceof AuthenticationError) {
|
|
162
|
-
return [false, error.message];
|
|
163
|
-
} else {
|
|
164
|
-
return [false, `Authentication error: ${error.message}`];
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
module.exports = {
|
|
170
|
-
UserAuthenticator,
|
|
171
|
-
AuthenticationError,
|
|
172
|
-
authenticateAndGetToken,
|
|
173
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Authentication module for the Stigmergy CLI system.
|
|
3
|
+
* Provides user authentication functionality including password hashing and token management.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const crypto = require('crypto');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Custom exception for authentication failures.
|
|
10
|
+
*/
|
|
11
|
+
class AuthenticationError extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'AuthenticationError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Handles user authentication operations including registration, login, and session management.
|
|
20
|
+
*/
|
|
21
|
+
class UserAuthenticator {
|
|
22
|
+
/**
|
|
23
|
+
* Create a new UserAuthenticator instance.
|
|
24
|
+
*/
|
|
25
|
+
constructor() {
|
|
26
|
+
// In production, this would be stored in a secure database
|
|
27
|
+
this._users = new Map();
|
|
28
|
+
this._sessions = new Map();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Register a new user with the provided username and password.
|
|
33
|
+
*
|
|
34
|
+
* @param {string} username - The user's username
|
|
35
|
+
* @param {string} password - The user's password
|
|
36
|
+
* @returns {boolean} True if registration successful, false if username already exists
|
|
37
|
+
* @throws {Error} If username or password is invalid
|
|
38
|
+
*/
|
|
39
|
+
registerUser(username, password) {
|
|
40
|
+
if (!username || !password) {
|
|
41
|
+
throw new Error('Username and password cannot be empty');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (username.length < 3) {
|
|
45
|
+
throw new Error('Username must be at least 3 characters long');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (password.length < 8) {
|
|
49
|
+
throw new Error('Password must be at least 8 characters long');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (this._users.has(username)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Hash the password with a salt
|
|
57
|
+
const salt = crypto.randomBytes(16).toString('hex');
|
|
58
|
+
const passwordHash = this._hashPassword(password, salt);
|
|
59
|
+
|
|
60
|
+
this._users.set(username, {
|
|
61
|
+
passwordHash: passwordHash,
|
|
62
|
+
salt: salt,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Authenticate a user with the provided credentials.
|
|
70
|
+
*
|
|
71
|
+
* @param {string} username - The user's username
|
|
72
|
+
* @param {string} password - The user's password
|
|
73
|
+
* @returns {string} Session token if authentication is successful
|
|
74
|
+
* @throws {AuthenticationError} If authentication fails
|
|
75
|
+
*/
|
|
76
|
+
authenticateUser(username, password) {
|
|
77
|
+
if (!this._users.has(username)) {
|
|
78
|
+
throw new AuthenticationError('Invalid username or password');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const userData = this._users.get(username);
|
|
82
|
+
const passwordHash = this._hashPassword(password, userData.salt);
|
|
83
|
+
|
|
84
|
+
if (passwordHash !== userData.passwordHash) {
|
|
85
|
+
throw new AuthenticationError('Invalid username or password');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Generate session token
|
|
89
|
+
const sessionToken = crypto.randomBytes(32).toString('base64url');
|
|
90
|
+
this._sessions.set(sessionToken, {
|
|
91
|
+
username: username,
|
|
92
|
+
createdAt: Date.now(),
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
return sessionToken;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Validate a session token and return the associated username.
|
|
100
|
+
*
|
|
101
|
+
* @param {string} sessionToken - The session token to validate
|
|
102
|
+
* @returns {string|null} Username if session is valid, null otherwise
|
|
103
|
+
*/
|
|
104
|
+
validateSession(sessionToken) {
|
|
105
|
+
if (!this._sessions.has(sessionToken)) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// In production, you would check session expiration here
|
|
110
|
+
return this._sessions.get(sessionToken).username;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Invalidate a session token.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} sessionToken - The session token to invalidate
|
|
117
|
+
* @returns {boolean} True if session was invalidated, false if token was not found
|
|
118
|
+
*/
|
|
119
|
+
logout(sessionToken) {
|
|
120
|
+
if (this._sessions.has(sessionToken)) {
|
|
121
|
+
this._sessions.delete(sessionToken);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Hash a password with the provided salt using PBKDF2.
|
|
129
|
+
*
|
|
130
|
+
* @param {string} password - The password to hash
|
|
131
|
+
* @param {string} salt - The salt to use for hashing
|
|
132
|
+
* @returns {string} The hashed password
|
|
133
|
+
* @private
|
|
134
|
+
*/
|
|
135
|
+
_hashPassword(password, salt) {
|
|
136
|
+
return crypto
|
|
137
|
+
.pbkdf2Sync(
|
|
138
|
+
password,
|
|
139
|
+
salt,
|
|
140
|
+
100000, // iterations
|
|
141
|
+
32, // key length
|
|
142
|
+
'sha256', // digest
|
|
143
|
+
)
|
|
144
|
+
.toString('hex');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Helper function to authenticate a user and return a session token.
|
|
150
|
+
*
|
|
151
|
+
* @param {UserAuthenticator} authenticator - The authenticator instance
|
|
152
|
+
* @param {string} username - The user's username
|
|
153
|
+
* @param {string} password - The user's password
|
|
154
|
+
* @returns {[boolean, string]} A tuple containing success status and message/token
|
|
155
|
+
*/
|
|
156
|
+
function authenticateAndGetToken(authenticator, username, password) {
|
|
157
|
+
try {
|
|
158
|
+
const token = authenticator.authenticateUser(username, password);
|
|
159
|
+
return [true, token];
|
|
160
|
+
} catch (error) {
|
|
161
|
+
if (error instanceof AuthenticationError) {
|
|
162
|
+
return [false, error.message];
|
|
163
|
+
} else {
|
|
164
|
+
return [false, `Authentication error: ${error.message}`];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = {
|
|
170
|
+
UserAuthenticator,
|
|
171
|
+
AuthenticationError,
|
|
172
|
+
authenticateAndGetToken,
|
|
173
|
+
};
|