step-node-agent 3.28.4 → 3.29.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.
- package/AgentConf.yaml +3 -1
- package/api/filemanager/filemanager.js +24 -1
- package/middleware/jwtAuth.js +37 -0
- package/node_modules/resolve/.eslintrc +1 -1
- package/node_modules/resolve/.github/INCIDENT_RESPONSE_PROCESS.md +119 -0
- package/node_modules/resolve/.github/THREAT_MODEL.md +74 -0
- package/node_modules/resolve/SECURITY.md +9 -1
- package/node_modules/resolve/lib/async.js +8 -4
- package/node_modules/resolve/lib/core.json +1 -1
- package/node_modules/resolve/lib/node-modules-paths.js +5 -2
- package/node_modules/resolve/lib/sync.js +7 -3
- package/node_modules/resolve/package.json +5 -5
- package/package.json +2 -1
- package/server.js +27 -8
- package/utils/jwtUtils.js +21 -0
package/AgentConf.yaml
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
agentPort: '8082'
|
|
2
2
|
gridHost: http://localhost:8081
|
|
3
|
+
#gridSecurity:
|
|
4
|
+
# jwtSecretKey: 6S7lhTV89ENqZqQXFgcpFSX8anpbosW/CSBe30l8NCQ=
|
|
3
5
|
registrationPeriod: 1000
|
|
4
6
|
tokenGroups:
|
|
5
7
|
- capacity: 10
|
|
@@ -10,4 +12,4 @@ tokenGroups:
|
|
|
10
12
|
properties:
|
|
11
13
|
myProp1: myDefaultValue
|
|
12
14
|
myProp2: myValue2
|
|
13
|
-
keywords: keywords/keywords.js;
|
|
15
|
+
keywords: keywords/keywords.js;
|
|
@@ -2,7 +2,10 @@ module.exports = function FileManager (agentContext) {
|
|
|
2
2
|
const fs = require('fs')
|
|
3
3
|
const shell = require('shelljs')
|
|
4
4
|
const http = require('http')
|
|
5
|
+
const https = require('https')
|
|
6
|
+
const url = require('url')
|
|
5
7
|
const unzip = require('unzip-stream')
|
|
8
|
+
const jwtUtils = require('../../utils/jwtUtils')
|
|
6
9
|
|
|
7
10
|
let exports = {}
|
|
8
11
|
const filemanagerPath = agentContext.properties['filemanagerPath'] ? agentContext.properties['filemanagerPath'] : 'filemanager'
|
|
@@ -99,7 +102,25 @@ module.exports = function FileManager (agentContext) {
|
|
|
99
102
|
|
|
100
103
|
function getKeywordFile (controllerFileUrl, targetDir) {
|
|
101
104
|
return new Promise(function (resolve, reject) {
|
|
102
|
-
|
|
105
|
+
const parsedUrl = url.parse(controllerFileUrl)
|
|
106
|
+
const httpModule = parsedUrl.protocol === 'https:' ? https : http
|
|
107
|
+
|
|
108
|
+
const requestOptions = {
|
|
109
|
+
hostname: parsedUrl.hostname,
|
|
110
|
+
port: parsedUrl.port,
|
|
111
|
+
path: parsedUrl.path,
|
|
112
|
+
method: 'GET'
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Add bearer token if gridSecurity is configured
|
|
116
|
+
const token = jwtUtils.generateJwtToken(agentContext.gridSecurity, 300); // 5 minutes expiration
|
|
117
|
+
if (token) {
|
|
118
|
+
requestOptions.headers = {
|
|
119
|
+
'Authorization': 'Bearer ' + token
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const req = httpModule.request(requestOptions, (resp) => {
|
|
103
124
|
const filename = parseName(resp.headers)
|
|
104
125
|
const filepath = targetDir + '/' + filename
|
|
105
126
|
if (isDir(resp.headers) || filename.toUpperCase().endsWith('ZIP')) {
|
|
@@ -112,6 +133,8 @@ module.exports = function FileManager (agentContext) {
|
|
|
112
133
|
console.log('Error: ' + err.message)
|
|
113
134
|
reject(err)
|
|
114
135
|
})
|
|
136
|
+
|
|
137
|
+
req.end()
|
|
115
138
|
})
|
|
116
139
|
}
|
|
117
140
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const jwt = require('jsonwebtoken')
|
|
2
|
+
|
|
3
|
+
module.exports = function createJwtAuthMiddleware(gridSecurity) {
|
|
4
|
+
return function jwtAuthMiddleware(req, res, next) {
|
|
5
|
+
// Skip authentication for /running endpoint
|
|
6
|
+
if (req.path === '/running') {
|
|
7
|
+
return next();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Skip authentication if gridSecurity is not configured
|
|
11
|
+
if (!gridSecurity || !gridSecurity.jwtSecretKey) {
|
|
12
|
+
return next();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const authHeader = req.headers.authorization;
|
|
16
|
+
|
|
17
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
18
|
+
return res.status(401).json({ error: 'Missing or invalid Authorization header' });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const token = authHeader.substring(7); // Remove 'Bearer ' prefix
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const decoded = jwt.verify(token, gridSecurity.jwtSecretKey, { algorithms: ['HS256'] });
|
|
25
|
+
req.user = decoded;
|
|
26
|
+
next();
|
|
27
|
+
} catch (err) {
|
|
28
|
+
if (err.name === 'TokenExpiredError') {
|
|
29
|
+
return res.status(401).json({ error: 'Token expired' });
|
|
30
|
+
} else if (err.name === 'JsonWebTokenError') {
|
|
31
|
+
return res.status(401).json({ error: 'Invalid token' });
|
|
32
|
+
} else {
|
|
33
|
+
return res.status(500).json({ error: 'Token verification failed' });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Incident Response Process for **resolve**
|
|
2
|
+
|
|
3
|
+
## Reporting a Vulnerability
|
|
4
|
+
|
|
5
|
+
We take the security of **resolve** very seriously. If you believe you’ve found a security vulnerability, please inform us responsibly through coordinated disclosure.
|
|
6
|
+
|
|
7
|
+
### How to Report
|
|
8
|
+
|
|
9
|
+
> **Do not** report security vulnerabilities through public GitHub issues, discussions, or social media.
|
|
10
|
+
|
|
11
|
+
Instead, please use one of these secure channels:
|
|
12
|
+
|
|
13
|
+
1. **GitHub Security Advisories**
|
|
14
|
+
Use the **Report a vulnerability** button in the Security tab of the [browserify/resolve repository](https://github.com/browserify/resolve).
|
|
15
|
+
|
|
16
|
+
2. **Email**
|
|
17
|
+
Follow the posted [Security Policy](https://github.com/browserify/resolve/security/policy).
|
|
18
|
+
|
|
19
|
+
### What to Include
|
|
20
|
+
|
|
21
|
+
**Required Information:**
|
|
22
|
+
- Brief description of the vulnerability type
|
|
23
|
+
- Affected version(s) and components
|
|
24
|
+
- Steps to reproduce the issue
|
|
25
|
+
- Impact assessment (what an attacker could achieve)
|
|
26
|
+
- Confirm the issue is not present in test files (in other words, only via the official entry points in `exports`)
|
|
27
|
+
|
|
28
|
+
**Helpful Additional Details:**
|
|
29
|
+
- Full paths of affected source files
|
|
30
|
+
- Specific commit or branch where the issue exists
|
|
31
|
+
- Required configuration to reproduce
|
|
32
|
+
- Proof-of-concept code (if available)
|
|
33
|
+
- Suggested mitigation or fix
|
|
34
|
+
|
|
35
|
+
## Our Response Process
|
|
36
|
+
|
|
37
|
+
**Timeline Commitments:**
|
|
38
|
+
- **Initial acknowledgment**: Within 24 hours
|
|
39
|
+
- **Detailed response**: Within 3 business days
|
|
40
|
+
- **Status updates**: Every 7 days until resolved
|
|
41
|
+
- **Resolution target**: 90 days for most issues
|
|
42
|
+
|
|
43
|
+
**What We’ll Do:**
|
|
44
|
+
1. Acknowledge your report and assign a tracking ID
|
|
45
|
+
2. Assess the vulnerability and determine severity
|
|
46
|
+
3. Develop and test a fix
|
|
47
|
+
4. Coordinate disclosure timeline with you
|
|
48
|
+
5. Release a security update and publish an advisory and CVE
|
|
49
|
+
6. Credit you in our security advisory (if desired)
|
|
50
|
+
|
|
51
|
+
## Disclosure Policy
|
|
52
|
+
|
|
53
|
+
- **Coordinated disclosure**: We’ll work with you on timing
|
|
54
|
+
- **Typical timeline**: 90 days from report to public disclosure
|
|
55
|
+
- **Early disclosure**: If actively exploited
|
|
56
|
+
- **Delayed disclosure**: For complex issues
|
|
57
|
+
|
|
58
|
+
## Scope
|
|
59
|
+
|
|
60
|
+
**In Scope:**
|
|
61
|
+
- **resolve** package (all supported versions)
|
|
62
|
+
- Official examples and documentation
|
|
63
|
+
- Core resolution APIs
|
|
64
|
+
- Dependencies with direct security implications
|
|
65
|
+
|
|
66
|
+
**Out of Scope:**
|
|
67
|
+
- Third-party wrappers or extensions
|
|
68
|
+
- Bundler-specific integrations
|
|
69
|
+
- Social engineering or physical attacks
|
|
70
|
+
- Theoretical vulnerabilities without practical exploitation
|
|
71
|
+
- Issues in non-production files
|
|
72
|
+
|
|
73
|
+
## Security Measures
|
|
74
|
+
|
|
75
|
+
**Our Commitments:**
|
|
76
|
+
- Regular vulnerability scanning via `npm audit`
|
|
77
|
+
- Automated security checks in CI/CD (GitHub Actions)
|
|
78
|
+
- Secure coding practices and mandatory code review
|
|
79
|
+
- Prompt patch releases for critical issues
|
|
80
|
+
|
|
81
|
+
**User Responsibilities:**
|
|
82
|
+
- Keep **resolve** updated
|
|
83
|
+
- Monitor dependency vulnerabilities
|
|
84
|
+
- Follow secure configuration guidelines for module resolution
|
|
85
|
+
|
|
86
|
+
## Legal Safe Harbor
|
|
87
|
+
|
|
88
|
+
**We will NOT:**
|
|
89
|
+
- Initiate legal action
|
|
90
|
+
- Contact law enforcement
|
|
91
|
+
- Suspend or terminate your access
|
|
92
|
+
|
|
93
|
+
**You must:**
|
|
94
|
+
- Only test against your own installations
|
|
95
|
+
- Not access, modify, or delete user data
|
|
96
|
+
- Not degrade service availability
|
|
97
|
+
- Not publicly disclose before coordinated disclosure
|
|
98
|
+
- Act in good faith
|
|
99
|
+
|
|
100
|
+
## Recognition
|
|
101
|
+
|
|
102
|
+
- **Advisory Credits**: Credit in GitHub Security Advisories (unless anonymous)
|
|
103
|
+
|
|
104
|
+
## Security Updates
|
|
105
|
+
|
|
106
|
+
**Stay Informed:**
|
|
107
|
+
- Subscribe to npm updates for **resolve**
|
|
108
|
+
- Enable GitHub Security Advisory notifications
|
|
109
|
+
|
|
110
|
+
**Update Process:**
|
|
111
|
+
- Patch releases (e.g., 1.22.10 → 1.22.11)
|
|
112
|
+
- Out-of-band releases for critical issues
|
|
113
|
+
- Advisories via GitHub Security Advisories
|
|
114
|
+
|
|
115
|
+
## Contact Information
|
|
116
|
+
|
|
117
|
+
- **Security reports**: Security tab of [browserify/resolve](https://github.com/browserify/resolve/security)
|
|
118
|
+
- **General inquiries**: GitHub Discussions or Issues
|
|
119
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
## Threat Model for resolve (module path resolution library)
|
|
2
|
+
|
|
3
|
+
### 1. Library Overview
|
|
4
|
+
|
|
5
|
+
- **Library Name:** resolve
|
|
6
|
+
- **Brief Description:** Implements Node.js `require.resolve()` algorithm for synchronous and asynchronous file path resolution. Used to locate modules and files in Node.js projects.
|
|
7
|
+
- **Key Public APIs/Functions:** `resolve.sync()` / `resolve/sync`, `resolve()` / `resolve/async`
|
|
8
|
+
|
|
9
|
+
### 2. Define Scope
|
|
10
|
+
|
|
11
|
+
This threat model focuses on the core path resolution algorithm, including filesystem interaction, option handling, and cache management.
|
|
12
|
+
|
|
13
|
+
### 3. Conceptual System Diagram
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Caller Application → resolve(id, options) → Resolution Algorithm → File System
|
|
17
|
+
│
|
|
18
|
+
└→ Options Handling
|
|
19
|
+
└→ Cache System
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Trust Boundaries:**
|
|
23
|
+
- **Input module IDs:** May come from untrusted sources (user input, configuration)
|
|
24
|
+
- **Filesystem access:** The library interacts with the filesystem to resolve paths
|
|
25
|
+
- **Options:** Provided by the caller
|
|
26
|
+
- **Cache:** Used to improve performance, but could be a vector for tampering or information disclosure if not handled securely
|
|
27
|
+
|
|
28
|
+
### 4. Identify Assets
|
|
29
|
+
|
|
30
|
+
- **Integrity of resolution output:** Ensure correct and safe file path matching.
|
|
31
|
+
- **Confidentiality of configuration:** Prevent sensitive path information from being leaked.
|
|
32
|
+
- **Availability/performance for host application:** Prevent crashes or resource exhaustion.
|
|
33
|
+
- **Security of host application:** Prevent path traversal or unintended filesystem access.
|
|
34
|
+
- **Reputation of library:** Maintain trust by avoiding supply chain attacks and vulnerabilities[1][3][4].
|
|
35
|
+
|
|
36
|
+
### 5. Identify Threats
|
|
37
|
+
|
|
38
|
+
| Component / API / Interaction | S | T | R | I | D | E |
|
|
39
|
+
|-----------------------------------------------------|----|----|----|----|----|----|
|
|
40
|
+
| Public API Call (`resolve/async`, `resolve/sync`) | ✓ | ✓ | – | ✓ | – | – |
|
|
41
|
+
| Filesystem Access | – | ✓ | – | ✓ | ✓ | – |
|
|
42
|
+
| Options Handling | ✓ | ✓ | – | ✓ | – | – |
|
|
43
|
+
| Cache System | – | ✓ | – | ✓ | – | – |
|
|
44
|
+
|
|
45
|
+
**Key Threats:**
|
|
46
|
+
- **Spoofing:** Malicious module IDs mimicking legitimate packages, or spoofing configuration options[1].
|
|
47
|
+
- **Tampering:** Caller-provided paths altering resolution order, or cache tampering leading to incorrect results[1][4].
|
|
48
|
+
- **Information Disclosure:** Error messages revealing filesystem structure or sensitive paths[1].
|
|
49
|
+
- **Denial of Service:** Recursive or excessive resolution exhausting filesystem handles or causing application crashes[1].
|
|
50
|
+
- **Path Traversal:** Malicious input allowing access to files outside the intended directory[4].
|
|
51
|
+
|
|
52
|
+
### 6. Mitigation/Countermeasures
|
|
53
|
+
|
|
54
|
+
| Threat Identified | Proposed Mitigation |
|
|
55
|
+
|--------------------------------------------|---------------------|
|
|
56
|
+
| Spoofing (malicious module IDs/config) | Sanitize input IDs; validate against known patterns; restrict `basedir` to app-controlled paths[1][4]. |
|
|
57
|
+
| Tampering (path traversal, cache) | Validate input IDs for directory escapes; secure cache reads/writes; restrict cache to trusted sources[1][4]. |
|
|
58
|
+
| Information Disclosure (error messages) | Generic "not found" errors without internal paths; avoid exposing sensitive configuration in errors[1]. |
|
|
59
|
+
| Denial of Service (resource exhaustion) | Limit recursive resolution depth; implement timeout; monitor for excessive filesystem operations[1]. |
|
|
60
|
+
|
|
61
|
+
### 7. Risk Ranking
|
|
62
|
+
|
|
63
|
+
- **High:** Path traversal via malicious IDs (if not properly mitigated)
|
|
64
|
+
- **Medium:** Cache tampering or spoofing (if cache is not secured)
|
|
65
|
+
- **Low:** Information disclosure in errors (if error handling is generic)
|
|
66
|
+
|
|
67
|
+
### 8. Next Steps & Review
|
|
68
|
+
|
|
69
|
+
1. **Implement input sanitization for module IDs and configuration.**
|
|
70
|
+
2. **Add resolution depth limiting and timeout.**
|
|
71
|
+
3. **Audit cache handling for race conditions and tampering.**
|
|
72
|
+
4. **Regularly review dependencies for vulnerabilities.**
|
|
73
|
+
5. **Keep documentation and threat model up to date.**
|
|
74
|
+
6. **Monitor for new threats as the ecosystem and library evolve[1][3].**
|
|
@@ -1,3 +1,11 @@
|
|
|
1
1
|
# Security
|
|
2
2
|
|
|
3
|
-
Please email [@ljharb](https://github.com/ljharb) or see https://tidelift.com/security if you have a potential security vulnerability to report.
|
|
3
|
+
Please file a private vulnerability via GitHub, email [@ljharb](https://github.com/ljharb), or see https://tidelift.com/security if you have a potential security vulnerability to report.
|
|
4
|
+
|
|
5
|
+
## Incident Response
|
|
6
|
+
|
|
7
|
+
See our [Incident Response Process](.github/INCIDENT_RESPONSE_PROCESS.md).
|
|
8
|
+
|
|
9
|
+
## Threat Model
|
|
10
|
+
|
|
11
|
+
See [THREAT_MODEL.md](./THREAT_MODEL.md).
|
|
@@ -8,6 +8,10 @@ var isCore = require('is-core-module');
|
|
|
8
8
|
|
|
9
9
|
var realpathFS = process.platform !== 'win32' && fs.realpath && typeof fs.realpath.native === 'function' ? fs.realpath.native : fs.realpath;
|
|
10
10
|
|
|
11
|
+
var relativePathRegex = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/;
|
|
12
|
+
var windowsDriveRegex = /^\w:[/\\]*$/;
|
|
13
|
+
var nodeModulesRegex = /[/\\]node_modules[/\\]*$/;
|
|
14
|
+
|
|
11
15
|
var homedir = getHomedir();
|
|
12
16
|
var defaultPaths = function () {
|
|
13
17
|
return [
|
|
@@ -124,10 +128,10 @@ module.exports = function resolve(x, options, callback) {
|
|
|
124
128
|
|
|
125
129
|
var res;
|
|
126
130
|
function init(basedir) {
|
|
127
|
-
if (
|
|
131
|
+
if (relativePathRegex.test(x)) {
|
|
128
132
|
res = path.resolve(basedir, x);
|
|
129
133
|
if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/';
|
|
130
|
-
if (
|
|
134
|
+
if (x.slice(-1) === '/' && res === basedir) {
|
|
131
135
|
loadAsDirectory(res, opts.package, onfile);
|
|
132
136
|
} else loadAsFile(res, opts.package, onfile);
|
|
133
137
|
} else if (includeCoreModules && isCore(x)) {
|
|
@@ -215,10 +219,10 @@ module.exports = function resolve(x, options, callback) {
|
|
|
215
219
|
|
|
216
220
|
function loadpkg(dir, cb) {
|
|
217
221
|
if (dir === '' || dir === '/') return cb(null);
|
|
218
|
-
if (process.platform === 'win32' &&
|
|
222
|
+
if (process.platform === 'win32' && windowsDriveRegex.test(dir)) {
|
|
219
223
|
return cb(null);
|
|
220
224
|
}
|
|
221
|
-
if (
|
|
225
|
+
if (nodeModulesRegex.test(dir)) return cb(null);
|
|
222
226
|
|
|
223
227
|
maybeRealpath(realpath, dir, opts, function (unwrapErr, pkgdir) {
|
|
224
228
|
if (unwrapErr) return loadpkg(path.dirname(dir), cb);
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"node:repl": [">= 14.18 && < 15", ">= 16"],
|
|
92
92
|
"node:sea": [">= 20.12 && < 21", ">= 21.7"],
|
|
93
93
|
"smalloc": ">= 0.11.5 && < 3",
|
|
94
|
-
"node:sqlite": ">= 23.4",
|
|
94
|
+
"node:sqlite": [">= 22.13 && < 23", ">= 23.4"],
|
|
95
95
|
"_stream_duplex": ">= 0.9.4",
|
|
96
96
|
"node:_stream_duplex": [">= 14.18 && < 15", ">= 16"],
|
|
97
97
|
"_stream_transform": ">= 0.9.4",
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
var path = require('path');
|
|
2
2
|
var parse = path.parse || require('path-parse'); // eslint-disable-line global-require
|
|
3
3
|
|
|
4
|
+
var driveLetterRegex = /^([A-Za-z]:)/;
|
|
5
|
+
var uncPathRegex = /^\\\\/;
|
|
6
|
+
|
|
4
7
|
var getNodeModulesDirs = function getNodeModulesDirs(absoluteStart, modules) {
|
|
5
8
|
var prefix = '/';
|
|
6
|
-
if (
|
|
9
|
+
if (driveLetterRegex.test(absoluteStart)) {
|
|
7
10
|
prefix = '';
|
|
8
|
-
} else if (
|
|
11
|
+
} else if (uncPathRegex.test(absoluteStart)) {
|
|
9
12
|
prefix = '\\\\';
|
|
10
13
|
}
|
|
11
14
|
|
|
@@ -8,6 +8,10 @@ var normalizeOptions = require('./normalize-options');
|
|
|
8
8
|
|
|
9
9
|
var realpathFS = process.platform !== 'win32' && fs.realpathSync && typeof fs.realpathSync.native === 'function' ? fs.realpathSync.native : fs.realpathSync;
|
|
10
10
|
|
|
11
|
+
var relativePathRegex = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/;
|
|
12
|
+
var windowsDriveRegex = /^\w:[/\\]*$/;
|
|
13
|
+
var nodeModulesRegex = /[/\\]node_modules[/\\]*$/;
|
|
14
|
+
|
|
11
15
|
var homedir = getHomedir();
|
|
12
16
|
var defaultPaths = function () {
|
|
13
17
|
return [
|
|
@@ -96,7 +100,7 @@ module.exports = function resolveSync(x, options) {
|
|
|
96
100
|
// ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory
|
|
97
101
|
var absoluteStart = maybeRealpathSync(realpathSync, path.resolve(basedir), opts);
|
|
98
102
|
|
|
99
|
-
if (
|
|
103
|
+
if (relativePathRegex.test(x)) {
|
|
100
104
|
var res = path.resolve(absoluteStart, x);
|
|
101
105
|
if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/';
|
|
102
106
|
var m = loadAsFileSync(res) || loadAsDirectorySync(res);
|
|
@@ -137,10 +141,10 @@ module.exports = function resolveSync(x, options) {
|
|
|
137
141
|
|
|
138
142
|
function loadpkg(dir) {
|
|
139
143
|
if (dir === '' || dir === '/') return;
|
|
140
|
-
if (process.platform === 'win32' &&
|
|
144
|
+
if (process.platform === 'win32' && windowsDriveRegex.test(dir)) {
|
|
141
145
|
return;
|
|
142
146
|
}
|
|
143
|
-
if (
|
|
147
|
+
if (nodeModulesRegex.test(dir)) return;
|
|
144
148
|
|
|
145
149
|
var pkgfile = path.join(maybeRealpathSync(realpathSync, dir, opts), 'package.json');
|
|
146
150
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resolve",
|
|
3
3
|
"description": "resolve like require.resolve() on behalf of files asynchronously and synchronously",
|
|
4
|
-
"version": "1.22.
|
|
4
|
+
"version": "1.22.11",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "
|
|
7
|
+
"url": "ssh://github.com/browserify/resolve.git"
|
|
8
8
|
},
|
|
9
9
|
"bin": {
|
|
10
10
|
"resolve": "./bin/resolve"
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"test:multirepo": "cd ./test/resolver/multirepo && npm install && npm test"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@ljharb/eslint-config": "^21.
|
|
34
|
-
"array.prototype.map": "^1.0.
|
|
33
|
+
"@ljharb/eslint-config": "^21.2.0",
|
|
34
|
+
"array.prototype.map": "^1.0.8",
|
|
35
35
|
"copy-dir": "^1.3.0",
|
|
36
36
|
"eclint": "^2.8.1",
|
|
37
37
|
"eslint": "=8.8.0",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"url": "https://github.com/sponsors/ljharb"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"is-core-module": "^2.16.
|
|
60
|
+
"is-core-module": "^2.16.1",
|
|
61
61
|
"path-parse": "^1.0.7",
|
|
62
62
|
"supports-preserve-symlinks-flag": "^1.0.0"
|
|
63
63
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "step-node-agent",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.29.0",
|
|
4
4
|
"description": "The official STEP Agent implementation for Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"express": "^4.17.1",
|
|
33
33
|
"get-fqdn": "^1.0.0",
|
|
34
34
|
"http": "0.0.0",
|
|
35
|
+
"jsonwebtoken": "^9.0.2",
|
|
35
36
|
"minimist": "^1.2.5",
|
|
36
37
|
"npm": "^6.14.15",
|
|
37
38
|
"request": "^2.88.0",
|
package/server.js
CHANGED
|
@@ -4,7 +4,7 @@ const YAML = require('yaml')
|
|
|
4
4
|
|
|
5
5
|
let args = minimist(process.argv.slice(2), {
|
|
6
6
|
default: {
|
|
7
|
-
f: path.join(__dirname, 'AgentConf.
|
|
7
|
+
f: path.join(__dirname, 'AgentConf.yaml')
|
|
8
8
|
}
|
|
9
9
|
})
|
|
10
10
|
console.log('[Agent] Using arguments ' + JSON.stringify(args))
|
|
@@ -26,9 +26,10 @@ if(agentConfFileExt === '.yaml') {
|
|
|
26
26
|
console.log('[Agent] Creating agent context and tokens')
|
|
27
27
|
const uuid = require('uuid/v4')
|
|
28
28
|
const _ = require('underscore')
|
|
29
|
+
const jwtUtils = require('./utils/jwtUtils')
|
|
29
30
|
const agentType = 'node'
|
|
30
31
|
const agent = {id: uuid()}
|
|
31
|
-
let agentContext = { tokens: [], tokenSessions: [], tokenProperties: [], properties: agentConf.properties, controllerUrl: agentConf.gridHost }
|
|
32
|
+
let agentContext = { tokens: [], tokenSessions: [], tokenProperties: [], properties: agentConf.properties, controllerUrl: agentConf.gridHost, gridSecurity: agentConf.gridSecurity }
|
|
32
33
|
_.each(agentConf.tokenGroups, function (tokenGroup) {
|
|
33
34
|
const tokenConf = tokenGroup.tokenConf
|
|
34
35
|
let attributes = tokenConf.attributes
|
|
@@ -60,6 +61,11 @@ const bodyParser = require('body-parser')
|
|
|
60
61
|
app.use(bodyParser.urlencoded({extended: true}))
|
|
61
62
|
app.use(bodyParser.json())
|
|
62
63
|
|
|
64
|
+
// Apply JWT authentication middleware
|
|
65
|
+
const createJwtAuthMiddleware = require('./middleware/jwtAuth')
|
|
66
|
+
const jwtAuthMiddleware = createJwtAuthMiddleware(agentConf.gridSecurity)
|
|
67
|
+
app.use(jwtAuthMiddleware)
|
|
68
|
+
|
|
63
69
|
const routes = require('./api/routes/routes')
|
|
64
70
|
routes(app, agentContext)
|
|
65
71
|
|
|
@@ -72,19 +78,32 @@ startWithAgentUrl = function(agentUrl) {
|
|
|
72
78
|
const registrationPeriod = agentConf.registrationPeriod || 5000
|
|
73
79
|
const request = require('request')
|
|
74
80
|
setInterval(function () {
|
|
75
|
-
|
|
81
|
+
const requestOptions = {
|
|
76
82
|
uri: agentConf.gridHost + '/grid/register',
|
|
77
83
|
method: 'POST',
|
|
78
84
|
json: true,
|
|
79
85
|
body: { agentRef: { agentId: agent.id, agentUrl: agentUrl, agentType: agentType }, tokens: agentContext.tokens }
|
|
80
|
-
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Add bearer token if gridSecurity is configured
|
|
89
|
+
const token = jwtUtils.generateJwtToken(agentConf.gridSecurity, 3600); // 1 hour expiration
|
|
90
|
+
if (token) {
|
|
91
|
+
requestOptions.headers = {
|
|
92
|
+
'Authorization': 'Bearer ' + token
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
request(requestOptions, function (err, res, body) {
|
|
81
97
|
if (err) {
|
|
98
|
+
console.log("[Agent] Error while registering agent to grid")
|
|
82
99
|
console.log(err)
|
|
100
|
+
} else if (res.statusCode !== 204) {
|
|
101
|
+
console.log("[Agent] Failed to register agent: grid responded with status " + res.statusCode + (body != null ? ". Response body: " + JSON.stringify(body) : ""))
|
|
83
102
|
}
|
|
84
103
|
})
|
|
85
104
|
}, registrationPeriod)
|
|
86
|
-
|
|
87
|
-
console.log('[Agent] Successfully started on: ' + port)
|
|
105
|
+
|
|
106
|
+
console.log('[Agent] Successfully started on: ' + port)
|
|
88
107
|
}
|
|
89
108
|
|
|
90
109
|
if(agentConf.agentUrl) {
|
|
@@ -92,8 +111,8 @@ if(agentConf.agentUrl) {
|
|
|
92
111
|
} else {
|
|
93
112
|
const getFQDN = require('get-fqdn');
|
|
94
113
|
getFQDN().then(FQDN => {
|
|
95
|
-
startWithAgentUrl('http://' + FQDN + ':' + port)
|
|
114
|
+
startWithAgentUrl('http://' + FQDN + ':' + port)
|
|
96
115
|
}).catch(e => {
|
|
97
116
|
console.log('[Agent] Error while getting FQDN ' + e)
|
|
98
117
|
})
|
|
99
|
-
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const jwt = require('jsonwebtoken')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
generateJwtToken: function(gridSecurity, expirationSeconds) {
|
|
5
|
+
if (!gridSecurity || !gridSecurity.jwtSecretKey) {
|
|
6
|
+
return null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const now = Math.floor(Date.now() / 1000);
|
|
10
|
+
const expiration = now + expirationSeconds;
|
|
11
|
+
|
|
12
|
+
return jwt.sign(
|
|
13
|
+
{
|
|
14
|
+
iat: now,
|
|
15
|
+
exp: expiration
|
|
16
|
+
},
|
|
17
|
+
gridSecurity.jwtSecretKey,
|
|
18
|
+
{ algorithm: 'HS256' }
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|