@agirails/sdk 2.4.0 → 2.4.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/dist/config/pendingPublish.d.ts.map +1 -1
- package/dist/config/pendingPublish.js +13 -3
- package/dist/config/pendingPublish.js.map +1 -1
- package/dist/wallet/keystore.d.ts.map +1 -1
- package/dist/wallet/keystore.js +17 -7
- package/dist/wallet/keystore.js.map +1 -1
- package/package.json +2 -2
- package/src/config/pendingPublish.ts +15 -4
- package/src/wallet/keystore.ts +25 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pendingPublish.d.ts","sourceRoot":"","sources":["../../src/config/pendingPublish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAoBnD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qBAAqB;IACrB,OAAO,EAAE,CAAC,CAAC;IACX,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA+CD;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"pendingPublish.d.ts","sourceRoot":"","sources":["../../src/config/pendingPublish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAoBnD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,qBAAqB;IACrB,OAAO,EAAE,CAAC,CAAC;IACX,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA+CD;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CA6BhE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAgB1E;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAkB3D"}
|
|
@@ -80,8 +80,15 @@ exports.getPendingPublishPath = getPendingPublishPath;
|
|
|
80
80
|
*/
|
|
81
81
|
function savePendingPublish(pending) {
|
|
82
82
|
const dir = getActpDir();
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
// Verify .actp/ is a real directory (not a symlink — symlink attack prevention)
|
|
84
|
+
if ((0, fs_1.existsSync)(dir)) {
|
|
85
|
+
const stat = (0, fs_1.lstatSync)(dir);
|
|
86
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
87
|
+
throw new Error(`Security: ${dir} is not a real directory (symlink attack prevention)`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true, mode: 0o700 });
|
|
85
92
|
}
|
|
86
93
|
const serialized = {
|
|
87
94
|
version: pending.version,
|
|
@@ -93,7 +100,10 @@ function savePendingPublish(pending) {
|
|
|
93
100
|
...(pending.network ? { network: pending.network } : {}),
|
|
94
101
|
};
|
|
95
102
|
const filePath = getPendingPublishPath(pending.network);
|
|
96
|
-
|
|
103
|
+
const tmpPath = filePath + '.tmp';
|
|
104
|
+
// Atomic write: write to .tmp with restricted mode, then rename
|
|
105
|
+
(0, fs_1.writeFileSync)(tmpPath, JSON.stringify(serialized, null, 2), { mode: 0o600 });
|
|
106
|
+
(0, fs_1.renameSync)(tmpPath, filePath);
|
|
97
107
|
}
|
|
98
108
|
exports.savePendingPublish = savePendingPublish;
|
|
99
109
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pendingPublish.js","sourceRoot":"","sources":["../../src/config/pendingPublish.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAEH,
|
|
1
|
+
{"version":3,"file":"pendingPublish.js","sourceRoot":"","sources":["../../src/config/pendingPublish.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../src/wallet/keystore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"keystore.d.ts","sourceRoot":"","sources":["../../src/wallet/keystore.ts"],"names":[],"mappings":"AA4DA;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAyC7B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAY5E;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAGlC"}
|
package/dist/wallet/keystore.js
CHANGED
|
@@ -35,10 +35,15 @@ exports._clearCache = exports.getCachedAddress = exports.resolvePrivateKey = voi
|
|
|
35
35
|
const fs = __importStar(require("fs"));
|
|
36
36
|
const path = __importStar(require("path"));
|
|
37
37
|
const ethers_1 = require("ethers");
|
|
38
|
+
/** 30-minute TTL for cached private keys */
|
|
39
|
+
const CACHE_TTL_MS = 30 * 60 * 1000;
|
|
38
40
|
// Cache keyed by resolved keystorePath to support multiple stateDirectories
|
|
39
41
|
const _cache = new Map();
|
|
40
42
|
// Separate cache for env-var-resolved key (no path dependency)
|
|
41
43
|
let _envCache = null;
|
|
44
|
+
function isExpired(entry) {
|
|
45
|
+
return Date.now() >= entry.expiresAt;
|
|
46
|
+
}
|
|
42
47
|
/**
|
|
43
48
|
* Validate that stateDirectory doesn't escape expected boundaries.
|
|
44
49
|
* Guards against path traversal when stateDirectory comes from user input.
|
|
@@ -71,11 +76,11 @@ function validateRawKey(raw, source) {
|
|
|
71
76
|
async function resolvePrivateKey(stateDirectory) {
|
|
72
77
|
// 1. Env var (highest priority, backward compat)
|
|
73
78
|
if (process.env.ACTP_PRIVATE_KEY) {
|
|
74
|
-
if (_envCache)
|
|
79
|
+
if (_envCache && !isExpired(_envCache))
|
|
75
80
|
return _envCache.key;
|
|
76
81
|
const key = validateRawKey(process.env.ACTP_PRIVATE_KEY, 'ACTP_PRIVATE_KEY env var');
|
|
77
82
|
const address = new ethers_1.Wallet(key).address;
|
|
78
|
-
_envCache = { key, address };
|
|
83
|
+
_envCache = { key, address, expiresAt: Date.now() + CACHE_TTL_MS };
|
|
79
84
|
return key;
|
|
80
85
|
}
|
|
81
86
|
// 2. Resolve keystore path
|
|
@@ -86,10 +91,12 @@ async function resolvePrivateKey(stateDirectory) {
|
|
|
86
91
|
? path.join(stateDirectory, '.actp')
|
|
87
92
|
: path.join(process.cwd(), '.actp');
|
|
88
93
|
const keystorePath = path.resolve(actpDir, 'keystore.json');
|
|
89
|
-
// 3. Cache hit (keyed by resolved path)
|
|
94
|
+
// 3. Cache hit (keyed by resolved path, with TTL)
|
|
90
95
|
const cached = _cache.get(keystorePath);
|
|
91
|
-
if (cached)
|
|
96
|
+
if (cached && !isExpired(cached))
|
|
92
97
|
return cached.key;
|
|
98
|
+
if (cached)
|
|
99
|
+
_cache.delete(keystorePath); // expired
|
|
93
100
|
// 4. Keystore file
|
|
94
101
|
if (!fs.existsSync(keystorePath))
|
|
95
102
|
return undefined;
|
|
@@ -100,7 +107,7 @@ async function resolvePrivateKey(stateDirectory) {
|
|
|
100
107
|
}
|
|
101
108
|
const keystore = fs.readFileSync(keystorePath, 'utf-8');
|
|
102
109
|
const wallet = await ethers_1.Wallet.fromEncryptedJson(keystore, password);
|
|
103
|
-
_cache.set(keystorePath, { key: wallet.privateKey, address: wallet.address });
|
|
110
|
+
_cache.set(keystorePath, { key: wallet.privateKey, address: wallet.address, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
104
111
|
return wallet.privateKey;
|
|
105
112
|
}
|
|
106
113
|
exports.resolvePrivateKey = resolvePrivateKey;
|
|
@@ -110,14 +117,17 @@ exports.resolvePrivateKey = resolvePrivateKey;
|
|
|
110
117
|
*/
|
|
111
118
|
function getCachedAddress(stateDirectory) {
|
|
112
119
|
// Env var path
|
|
113
|
-
if (_envCache)
|
|
120
|
+
if (_envCache && !isExpired(_envCache))
|
|
114
121
|
return _envCache.address;
|
|
115
122
|
// Keystore path — look up by resolved path
|
|
116
123
|
const actpDir = stateDirectory
|
|
117
124
|
? path.join(stateDirectory, '.actp')
|
|
118
125
|
: path.join(process.cwd(), '.actp');
|
|
119
126
|
const keystorePath = path.resolve(actpDir, 'keystore.json');
|
|
120
|
-
|
|
127
|
+
const cached = _cache.get(keystorePath);
|
|
128
|
+
if (cached && !isExpired(cached))
|
|
129
|
+
return cached.address;
|
|
130
|
+
return undefined;
|
|
121
131
|
}
|
|
122
132
|
exports.getCachedAddress = getCachedAddress;
|
|
123
133
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keystore.js","sourceRoot":"","sources":["../../src/wallet/keystore.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;GAOG;AACH,uCAAyB;AACzB,2CAA6B;AAC7B,mCAAgC;AAEhC,4EAA4E;AAC5E,MAAM,MAAM,GAAG,IAAI,GAAG,
|
|
1
|
+
{"version":3,"file":"keystore.js","sourceRoot":"","sources":["../../src/wallet/keystore.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agirails/sdk",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"description": "AGIRAILS SDK for the ACTP (Agent Commerce Transaction Protocol) - Unified mock + blockchain support",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
},
|
|
72
72
|
"homepage": "https://github.com/agirails/sdk#readme",
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@aws-sdk/client-s3": "3.
|
|
74
|
+
"@aws-sdk/client-s3": "^3.989.0",
|
|
75
75
|
"@ethereum-attestation-service/eas-sdk": "1.6.1",
|
|
76
76
|
"@irys/sdk": "0.2.11",
|
|
77
77
|
"commander": "11.1.0",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* @module config/pendingPublish
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { readFileSync, writeFileSync, unlinkSync, existsSync, mkdirSync } from 'fs';
|
|
17
|
+
import { readFileSync, writeFileSync, unlinkSync, existsSync, mkdirSync, renameSync, lstatSync } from 'fs';
|
|
18
18
|
import { join } from 'path';
|
|
19
19
|
import { ServiceDescriptor } from '../types/agent';
|
|
20
20
|
|
|
@@ -135,8 +135,15 @@ export function getPendingPublishPath(network?: string): string {
|
|
|
135
135
|
*/
|
|
136
136
|
export function savePendingPublish(pending: PendingPublish): void {
|
|
137
137
|
const dir = getActpDir();
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
|
|
139
|
+
// Verify .actp/ is a real directory (not a symlink — symlink attack prevention)
|
|
140
|
+
if (existsSync(dir)) {
|
|
141
|
+
const stat = lstatSync(dir);
|
|
142
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
143
|
+
throw new Error(`Security: ${dir} is not a real directory (symlink attack prevention)`);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
140
147
|
}
|
|
141
148
|
|
|
142
149
|
const serialized: SerializedPendingPublish = {
|
|
@@ -150,7 +157,11 @@ export function savePendingPublish(pending: PendingPublish): void {
|
|
|
150
157
|
};
|
|
151
158
|
|
|
152
159
|
const filePath = getPendingPublishPath(pending.network);
|
|
153
|
-
|
|
160
|
+
const tmpPath = filePath + '.tmp';
|
|
161
|
+
|
|
162
|
+
// Atomic write: write to .tmp with restricted mode, then rename
|
|
163
|
+
writeFileSync(tmpPath, JSON.stringify(serialized, null, 2), { mode: 0o600 });
|
|
164
|
+
renameSync(tmpPath, filePath);
|
|
154
165
|
}
|
|
155
166
|
|
|
156
167
|
/**
|
package/src/wallet/keystore.ts
CHANGED
|
@@ -10,11 +10,24 @@ import * as fs from 'fs';
|
|
|
10
10
|
import * as path from 'path';
|
|
11
11
|
import { Wallet } from 'ethers';
|
|
12
12
|
|
|
13
|
+
/** 30-minute TTL for cached private keys */
|
|
14
|
+
const CACHE_TTL_MS = 30 * 60 * 1000;
|
|
15
|
+
|
|
16
|
+
interface CacheEntry {
|
|
17
|
+
key: string;
|
|
18
|
+
address: string;
|
|
19
|
+
expiresAt: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
13
22
|
// Cache keyed by resolved keystorePath to support multiple stateDirectories
|
|
14
|
-
const _cache = new Map<string,
|
|
23
|
+
const _cache = new Map<string, CacheEntry>();
|
|
15
24
|
|
|
16
25
|
// Separate cache for env-var-resolved key (no path dependency)
|
|
17
|
-
let _envCache:
|
|
26
|
+
let _envCache: CacheEntry | null = null;
|
|
27
|
+
|
|
28
|
+
function isExpired(entry: CacheEntry): boolean {
|
|
29
|
+
return Date.now() >= entry.expiresAt;
|
|
30
|
+
}
|
|
18
31
|
|
|
19
32
|
/**
|
|
20
33
|
* Validate that stateDirectory doesn't escape expected boundaries.
|
|
@@ -54,11 +67,11 @@ export async function resolvePrivateKey(
|
|
|
54
67
|
): Promise<string | undefined> {
|
|
55
68
|
// 1. Env var (highest priority, backward compat)
|
|
56
69
|
if (process.env.ACTP_PRIVATE_KEY) {
|
|
57
|
-
if (_envCache) return _envCache.key;
|
|
70
|
+
if (_envCache && !isExpired(_envCache)) return _envCache.key;
|
|
58
71
|
|
|
59
72
|
const key = validateRawKey(process.env.ACTP_PRIVATE_KEY, 'ACTP_PRIVATE_KEY env var');
|
|
60
73
|
const address = new Wallet(key).address;
|
|
61
|
-
_envCache = { key, address };
|
|
74
|
+
_envCache = { key, address, expiresAt: Date.now() + CACHE_TTL_MS };
|
|
62
75
|
return key;
|
|
63
76
|
}
|
|
64
77
|
|
|
@@ -71,9 +84,10 @@ export async function resolvePrivateKey(
|
|
|
71
84
|
: path.join(process.cwd(), '.actp');
|
|
72
85
|
const keystorePath = path.resolve(actpDir, 'keystore.json');
|
|
73
86
|
|
|
74
|
-
// 3. Cache hit (keyed by resolved path)
|
|
87
|
+
// 3. Cache hit (keyed by resolved path, with TTL)
|
|
75
88
|
const cached = _cache.get(keystorePath);
|
|
76
|
-
if (cached) return cached.key;
|
|
89
|
+
if (cached && !isExpired(cached)) return cached.key;
|
|
90
|
+
if (cached) _cache.delete(keystorePath); // expired
|
|
77
91
|
|
|
78
92
|
// 4. Keystore file
|
|
79
93
|
if (!fs.existsSync(keystorePath)) return undefined;
|
|
@@ -89,7 +103,7 @@ export async function resolvePrivateKey(
|
|
|
89
103
|
const keystore = fs.readFileSync(keystorePath, 'utf-8');
|
|
90
104
|
const wallet = await Wallet.fromEncryptedJson(keystore, password);
|
|
91
105
|
|
|
92
|
-
_cache.set(keystorePath, { key: wallet.privateKey, address: wallet.address });
|
|
106
|
+
_cache.set(keystorePath, { key: wallet.privateKey, address: wallet.address, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
93
107
|
return wallet.privateKey;
|
|
94
108
|
}
|
|
95
109
|
|
|
@@ -99,14 +113,16 @@ export async function resolvePrivateKey(
|
|
|
99
113
|
*/
|
|
100
114
|
export function getCachedAddress(stateDirectory?: string): string | undefined {
|
|
101
115
|
// Env var path
|
|
102
|
-
if (_envCache) return _envCache.address;
|
|
116
|
+
if (_envCache && !isExpired(_envCache)) return _envCache.address;
|
|
103
117
|
|
|
104
118
|
// Keystore path — look up by resolved path
|
|
105
119
|
const actpDir = stateDirectory
|
|
106
120
|
? path.join(stateDirectory, '.actp')
|
|
107
121
|
: path.join(process.cwd(), '.actp');
|
|
108
122
|
const keystorePath = path.resolve(actpDir, 'keystore.json');
|
|
109
|
-
|
|
123
|
+
const cached = _cache.get(keystorePath);
|
|
124
|
+
if (cached && !isExpired(cached)) return cached.address;
|
|
125
|
+
return undefined;
|
|
110
126
|
}
|
|
111
127
|
|
|
112
128
|
/**
|