@palmyr/cli 1.0.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/README.md +731 -0
- package/dist/admin-auth.d.ts +1 -0
- package/dist/admin-auth.js +52 -0
- package/dist/admin-auth.js.map +1 -0
- package/dist/app.d.ts +182 -0
- package/dist/app.js +218 -0
- package/dist/app.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +3495 -0
- package/dist/cli.js.map +1 -0
- package/dist/compute-ssh.d.ts +246 -0
- package/dist/compute-ssh.js +577 -0
- package/dist/compute-ssh.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.js +183 -0
- package/dist/config.js.map +1 -0
- package/dist/credential-store.d.ts +4 -0
- package/dist/credential-store.js +180 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/mascot-data.d.ts +1 -0
- package/dist/mascot-data.js +14 -0
- package/dist/mascot-data.js.map +1 -0
- package/dist/pay.d.ts +60 -0
- package/dist/pay.js +483 -0
- package/dist/pay.js.map +1 -0
- package/dist/sdk.d.ts +259 -0
- package/dist/sdk.js +944 -0
- package/dist/sdk.js.map +1 -0
- package/dist/social-queue.d.ts +125 -0
- package/dist/social-queue.js +340 -0
- package/dist/social-queue.js.map +1 -0
- package/dist/social-vault.d.ts +118 -0
- package/dist/social-vault.js +268 -0
- package/dist/social-vault.js.map +1 -0
- package/dist/social-worker.d.ts +43 -0
- package/dist/social-worker.js +155 -0
- package/dist/social-worker.js.map +1 -0
- package/dist/totp.d.ts +2 -0
- package/dist/totp.js +46 -0
- package/dist/totp.js.map +1 -0
- package/dist/ui.d.ts +77 -0
- package/dist/ui.js +441 -0
- package/dist/ui.js.map +1 -0
- package/dist/vault.d.ts +65 -0
- package/dist/vault.js +455 -0
- package/dist/vault.js.map +1 -0
- package/package.json +75 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export type Platform = 'twitter' | 'tiktok';
|
|
2
|
+
export type AccountStatus = 'ready' | 'warming' | 'locked' | 'suspended' | 'dead';
|
|
3
|
+
interface EncryptedBlob {
|
|
4
|
+
iv: string;
|
|
5
|
+
ciphertext: string;
|
|
6
|
+
tag: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SocialCredentials {
|
|
9
|
+
/** What goes in the platform's login field — often an email, sometimes a username. */
|
|
10
|
+
login?: string;
|
|
11
|
+
password: string;
|
|
12
|
+
/** The bind/recovery email that comes with the account. Used to receive verification codes. */
|
|
13
|
+
email?: string;
|
|
14
|
+
/** Password for the bind email inbox, so automation can poll it for verification codes. */
|
|
15
|
+
email_password?: string;
|
|
16
|
+
/** RFC 4648 base32 TOTP seed (when 2FA is enabled). */
|
|
17
|
+
totp_seed?: string;
|
|
18
|
+
/** Recovery codes, if provided. */
|
|
19
|
+
recovery_codes?: string[];
|
|
20
|
+
/** Canonical profile URL from the seller. Optional, informational. */
|
|
21
|
+
profile_url?: string;
|
|
22
|
+
/** X session cookie — 40-char hex. If present, skip form login entirely. */
|
|
23
|
+
auth_token?: string;
|
|
24
|
+
/** X CSRF cookie — 160-char hex. Paired with auth_token. */
|
|
25
|
+
ct0?: string;
|
|
26
|
+
/** TikTok main auth cookie (hex). Required for TikTok cookie-injection login. */
|
|
27
|
+
tiktok_sessionid?: string;
|
|
28
|
+
/** TikTok CSRF token cookie. */
|
|
29
|
+
tiktok_csrf?: string;
|
|
30
|
+
/** TikTok device fingerprint cookie — preserves IP/device consistency. */
|
|
31
|
+
tiktok_webid?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface SocialAccountFile {
|
|
34
|
+
id: string;
|
|
35
|
+
platform: Platform;
|
|
36
|
+
username: string;
|
|
37
|
+
previous_usernames: string[];
|
|
38
|
+
cred_crypto: EncryptedBlob;
|
|
39
|
+
/**
|
|
40
|
+
* Portable IPRoyal sticky-session key. Set when the account was seasoned
|
|
41
|
+
* server-side (e.g. pool accounts, where the first login happened before
|
|
42
|
+
* the buyer's vault existed). When present, every server op pins the
|
|
43
|
+
* residential IP to this key rather than the local `id` — so the buyer
|
|
44
|
+
* inherits the exact same IP the admin seasoned.
|
|
45
|
+
*/
|
|
46
|
+
proxy_session_id?: string;
|
|
47
|
+
/**
|
|
48
|
+
* ISO-3166 alpha-2 country code (lowercase). Drives the proxy exit country
|
|
49
|
+
* AND the browser locale/timezone when the server opens a session for this
|
|
50
|
+
* account. Stored at the top level (not in the encrypted credentials) so
|
|
51
|
+
* the server can read it without decrypting the vault blob.
|
|
52
|
+
*/
|
|
53
|
+
country?: string;
|
|
54
|
+
meta: {
|
|
55
|
+
acquired_at: string;
|
|
56
|
+
acquisition_source: 'import' | 'accsmarket' | 'pool' | string;
|
|
57
|
+
status: AccountStatus;
|
|
58
|
+
age_years?: number;
|
|
59
|
+
original_signup_country?: string;
|
|
60
|
+
last_action_at: string | null;
|
|
61
|
+
notes?: string;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export interface SocialAccountSummary {
|
|
65
|
+
id: string;
|
|
66
|
+
platform: Platform;
|
|
67
|
+
username: string;
|
|
68
|
+
status: AccountStatus;
|
|
69
|
+
acquired_at: string;
|
|
70
|
+
source: string;
|
|
71
|
+
last_action_at: string | null;
|
|
72
|
+
proxy_session_id?: string;
|
|
73
|
+
country?: string;
|
|
74
|
+
}
|
|
75
|
+
export declare function importAccount(platform: Platform, username: string, credentials: SocialCredentials, opts?: {
|
|
76
|
+
source?: string;
|
|
77
|
+
notes?: string;
|
|
78
|
+
proxy_session_id?: string;
|
|
79
|
+
country?: string;
|
|
80
|
+
}): SocialAccountSummary;
|
|
81
|
+
export declare function listAccounts(platform?: Platform): SocialAccountSummary[];
|
|
82
|
+
export declare function getAccount(platform: Platform, username: string): SocialAccountSummary | undefined;
|
|
83
|
+
export declare function removeAccount(platform: Platform, username: string): void;
|
|
84
|
+
export declare function renameAccount(platform: Platform, oldUsername: string, newUsername: string): SocialAccountSummary;
|
|
85
|
+
/**
|
|
86
|
+
* Decrypt and return credentials. Requires the session secret to be present
|
|
87
|
+
* in the OS credential store — i.e. the account must have been created on
|
|
88
|
+
* this machine. Use sparingly; prefer keeping creds out of memory.
|
|
89
|
+
*/
|
|
90
|
+
export declare function unlockCredentials(platform: Platform, username: string): SocialCredentials;
|
|
91
|
+
/**
|
|
92
|
+
* Update the status / notes / last_action_at fields on an account. Doesn't
|
|
93
|
+
* touch the encrypted credentials.
|
|
94
|
+
*/
|
|
95
|
+
export declare function updateMeta(platform: Platform, username: string, patch: Partial<SocialAccountFile['meta']>): void;
|
|
96
|
+
/**
|
|
97
|
+
* Return the proxy_session_id for an account, if any. Server ops include
|
|
98
|
+
* this so the residential IP lineage is preserved (essential for pool
|
|
99
|
+
* accounts where the admin seasoned the session from a specific IP).
|
|
100
|
+
*/
|
|
101
|
+
export declare function getProxySessionId(platform: Platform, username: string): string | undefined;
|
|
102
|
+
/** Return the stored ISO country code for an account (lowercase), if any. */
|
|
103
|
+
export declare function getCountry(platform: Platform, username: string): string | undefined;
|
|
104
|
+
export interface SocialSession {
|
|
105
|
+
account_id: string;
|
|
106
|
+
platform: Platform;
|
|
107
|
+
cookies: any[];
|
|
108
|
+
captured_at: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Persist a login session. Cookies are AES-GCM encrypted with the same per-
|
|
112
|
+
* account session secret that protects credentials — an attacker with only
|
|
113
|
+
* read access to ~/.palmyr/social/sessions/ gets ciphertext, not cookies.
|
|
114
|
+
*/
|
|
115
|
+
export declare function saveSession(accountId: string, platform: Platform, cookies: any[]): SocialSession;
|
|
116
|
+
export declare function loadSession(accountId: string): SocialSession | undefined;
|
|
117
|
+
export declare function sessionAgeHours(accountId: string): number | undefined;
|
|
118
|
+
export {};
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local encrypted vault for social account credentials (X, TikTok, etc.).
|
|
3
|
+
*
|
|
4
|
+
* Each account is stored as a JSON file in ~/.palmyr/social/accounts/<id>.json
|
|
5
|
+
* with public metadata (id, platform, username, status) alongside an
|
|
6
|
+
* AES-256-GCM encrypted `cred_crypto` blob containing email + password +
|
|
7
|
+
* TOTP seed + recovery codes.
|
|
8
|
+
*
|
|
9
|
+
* The decryption key is a per-account 32-byte session secret held in the OS
|
|
10
|
+
* credential store. An attacker with only the file cannot decrypt it; an
|
|
11
|
+
* attacker with only the credential store entry has no ciphertext to decrypt.
|
|
12
|
+
*/
|
|
13
|
+
import { randomBytes, createCipheriv, createDecipheriv } from 'crypto';
|
|
14
|
+
import { existsSync, readFileSync, readdirSync, writeFileSync, mkdirSync, unlinkSync } from 'fs';
|
|
15
|
+
import { join } from 'path';
|
|
16
|
+
import { homedir } from 'os';
|
|
17
|
+
import { storeSecret, retrieveSecret, deleteSecret } from './credential-store.js';
|
|
18
|
+
function getSocialDir() {
|
|
19
|
+
return process.env.PALMYR_SOCIAL_PATH || join(homedir(), '.palmyr', 'social');
|
|
20
|
+
}
|
|
21
|
+
function getAccountsDir() {
|
|
22
|
+
return join(getSocialDir(), 'accounts');
|
|
23
|
+
}
|
|
24
|
+
function ensureDirs() {
|
|
25
|
+
const root = getSocialDir();
|
|
26
|
+
if (!existsSync(root))
|
|
27
|
+
mkdirSync(root, { recursive: true });
|
|
28
|
+
const accounts = getAccountsDir();
|
|
29
|
+
if (!existsSync(accounts))
|
|
30
|
+
mkdirSync(accounts, { recursive: true });
|
|
31
|
+
const sessions = join(root, 'sessions');
|
|
32
|
+
if (!existsSync(sessions))
|
|
33
|
+
mkdirSync(sessions, { recursive: true });
|
|
34
|
+
const history = join(root, 'history');
|
|
35
|
+
if (!existsSync(history))
|
|
36
|
+
mkdirSync(history, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
function accountPath(id) {
|
|
39
|
+
return join(getAccountsDir(), `${id}.json`);
|
|
40
|
+
}
|
|
41
|
+
function newHexId() {
|
|
42
|
+
// 16 hex chars — unique enough for local scope, short enough to not be ugly.
|
|
43
|
+
return randomBytes(8).toString('hex');
|
|
44
|
+
}
|
|
45
|
+
function encrypt(plaintext, keyHex) {
|
|
46
|
+
const key = Buffer.from(keyHex, 'hex');
|
|
47
|
+
const iv = randomBytes(12);
|
|
48
|
+
const cipher = createCipheriv('aes-256-gcm', key, iv);
|
|
49
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
|
|
50
|
+
const tag = cipher.getAuthTag();
|
|
51
|
+
return {
|
|
52
|
+
iv: iv.toString('hex'),
|
|
53
|
+
ciphertext: ciphertext.toString('hex'),
|
|
54
|
+
tag: tag.toString('hex'),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function decrypt(blob, keyHex) {
|
|
58
|
+
const key = Buffer.from(keyHex, 'hex');
|
|
59
|
+
const decipher = createDecipheriv('aes-256-gcm', key, Buffer.from(blob.iv, 'hex'));
|
|
60
|
+
decipher.setAuthTag(Buffer.from(blob.tag, 'hex'));
|
|
61
|
+
let plaintext = decipher.update(blob.ciphertext, 'hex', 'utf8');
|
|
62
|
+
plaintext += decipher.final('utf8');
|
|
63
|
+
return plaintext;
|
|
64
|
+
}
|
|
65
|
+
function readAllAccounts() {
|
|
66
|
+
ensureDirs();
|
|
67
|
+
const dir = getAccountsDir();
|
|
68
|
+
return readdirSync(dir)
|
|
69
|
+
.filter(f => f.endsWith('.json'))
|
|
70
|
+
.map(f => JSON.parse(readFileSync(join(dir, f), 'utf8')));
|
|
71
|
+
}
|
|
72
|
+
function findByUsername(platform, username) {
|
|
73
|
+
return readAllAccounts().find(a => a.platform === platform && a.username === username);
|
|
74
|
+
}
|
|
75
|
+
function findById(id) {
|
|
76
|
+
const fpath = accountPath(id);
|
|
77
|
+
if (!existsSync(fpath))
|
|
78
|
+
return undefined;
|
|
79
|
+
return JSON.parse(readFileSync(fpath, 'utf8'));
|
|
80
|
+
}
|
|
81
|
+
function writeAccount(account) {
|
|
82
|
+
ensureDirs();
|
|
83
|
+
writeFileSync(accountPath(account.id), JSON.stringify(account, null, 2));
|
|
84
|
+
}
|
|
85
|
+
// ─── Public API ────────────────────────────────────────────────────────────
|
|
86
|
+
export function importAccount(platform, username, credentials, opts = {}) {
|
|
87
|
+
if (findByUsername(platform, username)) {
|
|
88
|
+
throw new Error(`${platform} account "${username}" already exists locally. Use 'remove' first if you want to re-import.`);
|
|
89
|
+
}
|
|
90
|
+
const id = newHexId();
|
|
91
|
+
const sessionSecret = randomBytes(32).toString('hex');
|
|
92
|
+
storeSecret(id, sessionSecret);
|
|
93
|
+
const account = {
|
|
94
|
+
id,
|
|
95
|
+
platform,
|
|
96
|
+
username,
|
|
97
|
+
previous_usernames: [],
|
|
98
|
+
cred_crypto: encrypt(JSON.stringify(credentials), sessionSecret),
|
|
99
|
+
proxy_session_id: opts.proxy_session_id,
|
|
100
|
+
country: opts.country ? opts.country.toLowerCase() : undefined,
|
|
101
|
+
meta: {
|
|
102
|
+
acquired_at: new Date().toISOString(),
|
|
103
|
+
acquisition_source: opts.source || 'import',
|
|
104
|
+
status: 'ready',
|
|
105
|
+
last_action_at: null,
|
|
106
|
+
notes: opts.notes,
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
writeAccount(account);
|
|
110
|
+
return summarise(account);
|
|
111
|
+
}
|
|
112
|
+
function summarise(acc) {
|
|
113
|
+
return {
|
|
114
|
+
id: acc.id,
|
|
115
|
+
platform: acc.platform,
|
|
116
|
+
username: acc.username,
|
|
117
|
+
status: acc.meta.status,
|
|
118
|
+
acquired_at: acc.meta.acquired_at,
|
|
119
|
+
source: acc.meta.acquisition_source,
|
|
120
|
+
last_action_at: acc.meta.last_action_at,
|
|
121
|
+
proxy_session_id: acc.proxy_session_id,
|
|
122
|
+
country: acc.country,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
export function listAccounts(platform) {
|
|
126
|
+
return readAllAccounts()
|
|
127
|
+
.filter(a => !platform || a.platform === platform)
|
|
128
|
+
.map(summarise);
|
|
129
|
+
}
|
|
130
|
+
export function getAccount(platform, username) {
|
|
131
|
+
const acc = findByUsername(platform, username);
|
|
132
|
+
if (!acc)
|
|
133
|
+
return undefined;
|
|
134
|
+
return summarise(acc);
|
|
135
|
+
}
|
|
136
|
+
export function removeAccount(platform, username) {
|
|
137
|
+
const acc = findByUsername(platform, username);
|
|
138
|
+
if (!acc)
|
|
139
|
+
throw new Error(`${platform} account "${username}" not found locally`);
|
|
140
|
+
deleteSecret(acc.id);
|
|
141
|
+
const fpath = accountPath(acc.id);
|
|
142
|
+
if (existsSync(fpath))
|
|
143
|
+
unlinkSync(fpath);
|
|
144
|
+
}
|
|
145
|
+
export function renameAccount(platform, oldUsername, newUsername) {
|
|
146
|
+
const acc = findByUsername(platform, oldUsername);
|
|
147
|
+
if (!acc)
|
|
148
|
+
throw new Error(`${platform} account "${oldUsername}" not found locally`);
|
|
149
|
+
if (findByUsername(platform, newUsername)) {
|
|
150
|
+
throw new Error(`${platform} account "${newUsername}" already exists — can't rename into an existing slot`);
|
|
151
|
+
}
|
|
152
|
+
acc.previous_usernames.push(acc.username);
|
|
153
|
+
acc.username = newUsername;
|
|
154
|
+
writeAccount(acc);
|
|
155
|
+
return summarise(acc);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Decrypt and return credentials. Requires the session secret to be present
|
|
159
|
+
* in the OS credential store — i.e. the account must have been created on
|
|
160
|
+
* this machine. Use sparingly; prefer keeping creds out of memory.
|
|
161
|
+
*/
|
|
162
|
+
export function unlockCredentials(platform, username) {
|
|
163
|
+
const acc = findByUsername(platform, username);
|
|
164
|
+
if (!acc)
|
|
165
|
+
throw new Error(`${platform} account "${username}" not found locally`);
|
|
166
|
+
const sessionSecret = retrieveSecret(acc.id);
|
|
167
|
+
if (!sessionSecret) {
|
|
168
|
+
throw new Error(`No session secret found for ${platform}/${username}. The account was likely imported on a different machine, ` +
|
|
169
|
+
`or the OS credential store was wiped. Re-import the account to restore access.`);
|
|
170
|
+
}
|
|
171
|
+
const json = decrypt(acc.cred_crypto, sessionSecret);
|
|
172
|
+
return JSON.parse(json);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Update the status / notes / last_action_at fields on an account. Doesn't
|
|
176
|
+
* touch the encrypted credentials.
|
|
177
|
+
*/
|
|
178
|
+
export function updateMeta(platform, username, patch) {
|
|
179
|
+
const acc = findByUsername(platform, username);
|
|
180
|
+
if (!acc)
|
|
181
|
+
throw new Error(`${platform} account "${username}" not found locally`);
|
|
182
|
+
acc.meta = { ...acc.meta, ...patch };
|
|
183
|
+
writeAccount(acc);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Return the proxy_session_id for an account, if any. Server ops include
|
|
187
|
+
* this so the residential IP lineage is preserved (essential for pool
|
|
188
|
+
* accounts where the admin seasoned the session from a specific IP).
|
|
189
|
+
*/
|
|
190
|
+
export function getProxySessionId(platform, username) {
|
|
191
|
+
return findByUsername(platform, username)?.proxy_session_id;
|
|
192
|
+
}
|
|
193
|
+
/** Return the stored ISO country code for an account (lowercase), if any. */
|
|
194
|
+
export function getCountry(platform, username) {
|
|
195
|
+
return findByUsername(platform, username)?.country;
|
|
196
|
+
}
|
|
197
|
+
function sessionPath(accountId) {
|
|
198
|
+
return join(getSocialDir(), 'sessions', `${accountId}.sess`);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Persist a login session. Cookies are AES-GCM encrypted with the same per-
|
|
202
|
+
* account session secret that protects credentials — an attacker with only
|
|
203
|
+
* read access to ~/.palmyr/social/sessions/ gets ciphertext, not cookies.
|
|
204
|
+
*/
|
|
205
|
+
export function saveSession(accountId, platform, cookies) {
|
|
206
|
+
ensureDirs();
|
|
207
|
+
const sessionSecret = retrieveSecret(accountId);
|
|
208
|
+
if (!sessionSecret) {
|
|
209
|
+
throw new Error(`Cannot encrypt session for ${accountId}: no session secret in the OS credential store. ` +
|
|
210
|
+
`Was the account imported on this machine?`);
|
|
211
|
+
}
|
|
212
|
+
const capturedAt = new Date().toISOString();
|
|
213
|
+
const payload = {
|
|
214
|
+
account_id: accountId,
|
|
215
|
+
platform,
|
|
216
|
+
captured_at: capturedAt,
|
|
217
|
+
cookies_crypto: encrypt(JSON.stringify(cookies), sessionSecret),
|
|
218
|
+
};
|
|
219
|
+
writeFileSync(sessionPath(accountId), JSON.stringify(payload, null, 2), { mode: 0o600 });
|
|
220
|
+
return { account_id: accountId, platform, cookies, captured_at: capturedAt };
|
|
221
|
+
}
|
|
222
|
+
export function loadSession(accountId) {
|
|
223
|
+
const fpath = sessionPath(accountId);
|
|
224
|
+
if (!existsSync(fpath))
|
|
225
|
+
return undefined;
|
|
226
|
+
const raw = JSON.parse(readFileSync(fpath, 'utf8'));
|
|
227
|
+
// Legacy (plaintext) sessions from before session encryption existed — migrate
|
|
228
|
+
// by re-saving encrypted when possible. Return as-is if the secret is missing.
|
|
229
|
+
if (raw.cookies && Array.isArray(raw.cookies)) {
|
|
230
|
+
const legacy = raw;
|
|
231
|
+
try {
|
|
232
|
+
saveSession(accountId, legacy.platform, legacy.cookies);
|
|
233
|
+
}
|
|
234
|
+
catch { }
|
|
235
|
+
return legacy;
|
|
236
|
+
}
|
|
237
|
+
const encFile = raw;
|
|
238
|
+
const sessionSecret = retrieveSecret(accountId);
|
|
239
|
+
if (!sessionSecret)
|
|
240
|
+
return undefined;
|
|
241
|
+
try {
|
|
242
|
+
const cookies = JSON.parse(decrypt(encFile.cookies_crypto, sessionSecret));
|
|
243
|
+
return {
|
|
244
|
+
account_id: encFile.account_id,
|
|
245
|
+
platform: encFile.platform,
|
|
246
|
+
cookies,
|
|
247
|
+
captured_at: encFile.captured_at,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
export function sessionAgeHours(accountId) {
|
|
255
|
+
const fpath = sessionPath(accountId);
|
|
256
|
+
if (!existsSync(fpath))
|
|
257
|
+
return undefined;
|
|
258
|
+
try {
|
|
259
|
+
const raw = JSON.parse(readFileSync(fpath, 'utf8'));
|
|
260
|
+
if (!raw.captured_at)
|
|
261
|
+
return undefined;
|
|
262
|
+
return (Date.now() - new Date(raw.captured_at).getTime()) / 1000 / 3600;
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=social-vault.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social-vault.js","sourceRoot":"","sources":["../social-vault.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker that consumes due scheduled items from cli/social-queue.ts and
|
|
3
|
+
* dispatches them via the existing paid X routes through the SDK.
|
|
4
|
+
*
|
|
5
|
+
* Designed to run inside the same Node process as the CLI — `agentos worker`
|
|
6
|
+
* keeps polling until SIGINT/SIGTERM. There's also a `--once` mode for cron.
|
|
7
|
+
*
|
|
8
|
+
* Failure classification routes back into the queue: retryable codes (rate
|
|
9
|
+
* limit, transient browser issue) get re-scheduled with exponential backoff;
|
|
10
|
+
* non-retryable codes (bad input, missing session) move to `failed[]`.
|
|
11
|
+
*/
|
|
12
|
+
import type { AgentOS } from './sdk.js';
|
|
13
|
+
import * as sq from './social-queue.js';
|
|
14
|
+
export interface DispatchResult {
|
|
15
|
+
ok: boolean;
|
|
16
|
+
result?: any;
|
|
17
|
+
error?: string;
|
|
18
|
+
retryable: boolean;
|
|
19
|
+
}
|
|
20
|
+
export declare function dispatchScheduledItem(item: sq.ScheduledItem, ao: AgentOS): Promise<DispatchResult>;
|
|
21
|
+
export interface TickSummary {
|
|
22
|
+
tickStartedAt: string;
|
|
23
|
+
processed: number;
|
|
24
|
+
succeeded: number;
|
|
25
|
+
failed: number;
|
|
26
|
+
results: Array<{
|
|
27
|
+
id: string;
|
|
28
|
+
account: string;
|
|
29
|
+
action: string;
|
|
30
|
+
ok: boolean;
|
|
31
|
+
error?: string;
|
|
32
|
+
retryable?: boolean;
|
|
33
|
+
result?: any;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export declare function runWorkerOnce(ao: AgentOS, accountFilter?: string): Promise<TickSummary>;
|
|
37
|
+
export interface WorkerLoopOptions {
|
|
38
|
+
intervalSec: number;
|
|
39
|
+
accountFilter?: string;
|
|
40
|
+
onLog: (msg: string) => void;
|
|
41
|
+
onTick?: (summary: TickSummary) => void;
|
|
42
|
+
}
|
|
43
|
+
export declare function runWorkerLoop(ao: AgentOS, opts: WorkerLoopOptions): Promise<void>;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import * as sq from './social-queue.js';
|
|
2
|
+
import * as sv from './social-vault.js';
|
|
3
|
+
/**
|
|
4
|
+
* Codes returned by social-operations.ts. Retryable ones get re-scheduled
|
|
5
|
+
* by the queue; the rest move to `failed[]` immediately.
|
|
6
|
+
*/
|
|
7
|
+
const RETRYABLE_CODES = new Set([
|
|
8
|
+
'RATE_LIMITED',
|
|
9
|
+
'UI_TIMEOUT',
|
|
10
|
+
'LAUNCH_FAILED',
|
|
11
|
+
'UNKNOWN',
|
|
12
|
+
]);
|
|
13
|
+
export async function dispatchScheduledItem(item, ao) {
|
|
14
|
+
// Resolve account + session from local vault. Session staleness is the
|
|
15
|
+
// worker's most common failure — surface it clearly so the user knows to
|
|
16
|
+
// re-login (and so it doesn't waste retry attempts).
|
|
17
|
+
const acc = sv.getAccount('twitter', item.account_username);
|
|
18
|
+
if (!acc) {
|
|
19
|
+
return {
|
|
20
|
+
ok: false,
|
|
21
|
+
retryable: false,
|
|
22
|
+
error: `Account "${item.account_username}" not found in local vault.`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const sess = sv.loadSession(acc.id);
|
|
26
|
+
if (!sess || !sess.cookies || sess.cookies.length === 0) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
retryable: false,
|
|
30
|
+
error: `No cached session for "${item.account_username}". Run: agentos twitter login ${item.account_username}`,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const psid = sv.getProxySessionId('twitter', item.account_username);
|
|
34
|
+
// Materialise media to wire format only at dispatch time (keeps the queue
|
|
35
|
+
// file small; scheduled items reference paths or URLs).
|
|
36
|
+
let mediaForWire;
|
|
37
|
+
if (item.media && item.media.length > 0) {
|
|
38
|
+
try {
|
|
39
|
+
mediaForWire = item.media.map(m => sq.materializeMediaRefForWire(m));
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
return { ok: false, retryable: false, error: `Media materialise failed: ${e.message}` };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Dispatch by action shape.
|
|
46
|
+
let data;
|
|
47
|
+
try {
|
|
48
|
+
if (item.action === 'post') {
|
|
49
|
+
data = await ao.socialTwitterPost(acc.id, sess.cookies, item.text || '', psid, item.community_id);
|
|
50
|
+
}
|
|
51
|
+
else if (item.action === 'post_thread') {
|
|
52
|
+
data = await ao.socialTwitterPostThread(acc.id, sess.cookies, item.texts || [], psid, item.community_id);
|
|
53
|
+
}
|
|
54
|
+
else if (item.action === 'post_media') {
|
|
55
|
+
data = await ao.socialTwitterPostWithMedia(acc.id, sess.cookies, item.text || '', mediaForWire || [], psid, item.community_id);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return { ok: false, retryable: false, error: `Unknown action: ${item.action}` };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
// Network/HTTP errors thrown from the SDK are retryable by default.
|
|
63
|
+
return { ok: false, retryable: true, error: e.message || String(e) };
|
|
64
|
+
}
|
|
65
|
+
if (!data?.success) {
|
|
66
|
+
const code = data?.error_code || 'UNKNOWN';
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
retryable: RETRYABLE_CODES.has(code),
|
|
70
|
+
error: `${data?.error || 'unknown error'} [${code}]`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Update last_action_at on the account so the local vault's freshness
|
|
74
|
+
// tracking stays accurate even when posting via the worker.
|
|
75
|
+
sv.updateMeta('twitter', item.account_username, { last_action_at: new Date().toISOString() });
|
|
76
|
+
return { ok: true, retryable: false, result: data.data || {} };
|
|
77
|
+
}
|
|
78
|
+
export async function runWorkerOnce(ao, accountFilter) {
|
|
79
|
+
const tickStartedAt = new Date().toISOString();
|
|
80
|
+
const due = sq.getDueScheduled().filter(i => !accountFilter || i.account_username === accountFilter);
|
|
81
|
+
const results = [];
|
|
82
|
+
for (const item of due) {
|
|
83
|
+
// markScheduledInProgress is the lock — if another worker already claimed
|
|
84
|
+
// this item, it returns false and we skip.
|
|
85
|
+
if (!sq.markScheduledInProgress(item.id))
|
|
86
|
+
continue;
|
|
87
|
+
const r = await dispatchScheduledItem(item, ao);
|
|
88
|
+
if (r.ok) {
|
|
89
|
+
sq.markScheduledPublished(item.id, r.result);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
sq.markScheduledFailed(item.id, r.error || 'unknown', r.retryable);
|
|
93
|
+
}
|
|
94
|
+
results.push({
|
|
95
|
+
id: item.id,
|
|
96
|
+
account: item.account_username,
|
|
97
|
+
action: item.action,
|
|
98
|
+
ok: r.ok,
|
|
99
|
+
error: r.error,
|
|
100
|
+
retryable: r.retryable,
|
|
101
|
+
result: r.result,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
tickStartedAt,
|
|
106
|
+
processed: results.length,
|
|
107
|
+
succeeded: results.filter(r => r.ok).length,
|
|
108
|
+
failed: results.filter(r => !r.ok).length,
|
|
109
|
+
results,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
export async function runWorkerLoop(ao, opts) {
|
|
113
|
+
let stopped = false;
|
|
114
|
+
const stop = (sig) => {
|
|
115
|
+
if (!stopped) {
|
|
116
|
+
stopped = true;
|
|
117
|
+
opts.onLog(`${sig} received, stopping after current tick`);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
process.on('SIGINT', () => stop('SIGINT'));
|
|
121
|
+
process.on('SIGTERM', () => stop('SIGTERM'));
|
|
122
|
+
opts.onLog(`Worker started (interval ${opts.intervalSec}s` +
|
|
123
|
+
(opts.accountFilter ? `, account ${opts.accountFilter}` : '') +
|
|
124
|
+
`)`);
|
|
125
|
+
while (!stopped) {
|
|
126
|
+
let summary;
|
|
127
|
+
try {
|
|
128
|
+
summary = await runWorkerOnce(ao, opts.accountFilter);
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
// A throw here is unusual (runWorkerOnce catches per-item errors).
|
|
132
|
+
// Log and keep the loop alive so a single bad tick doesn't kill the worker.
|
|
133
|
+
opts.onLog(`Tick crashed: ${e.message}`);
|
|
134
|
+
await sleep(opts.intervalSec * 1000);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
opts.onTick?.(summary);
|
|
138
|
+
if (summary.processed > 0) {
|
|
139
|
+
opts.onLog(`Tick: ${summary.succeeded}/${summary.processed} ok` +
|
|
140
|
+
(summary.failed > 0 ? `, ${summary.failed} failed` : ''));
|
|
141
|
+
for (const r of summary.results) {
|
|
142
|
+
opts.onLog(` - ${r.id} [${r.account}/${r.action}]: ${r.ok ? 'OK' : 'FAIL'} ` +
|
|
143
|
+
(r.ok ? JSON.stringify(r.result) : `${r.error}${r.retryable ? ' (will retry)' : ''}`));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (stopped)
|
|
147
|
+
break;
|
|
148
|
+
await sleep(opts.intervalSec * 1000);
|
|
149
|
+
}
|
|
150
|
+
opts.onLog('Worker stopped');
|
|
151
|
+
}
|
|
152
|
+
function sleep(ms) {
|
|
153
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=social-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"social-worker.js","sourceRoot":"","sources":["../social-worker.ts"],"names":[],"mappings":"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"}
|
package/dist/totp.d.ts
ADDED
package/dist/totp.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 6238 TOTP code derivation. Pure Node crypto, no external deps.
|
|
3
|
+
*
|
|
4
|
+
* Secret is a base32-encoded string (RFC 4648) — the format X / Google Auth /
|
|
5
|
+
* Authy exchange via QR codes. `code(secret)` returns the current 6-digit code
|
|
6
|
+
* for the 30-second window.
|
|
7
|
+
*/
|
|
8
|
+
import { createHmac } from 'crypto';
|
|
9
|
+
const BASE32_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
10
|
+
function base32Decode(input) {
|
|
11
|
+
const clean = input.replace(/=+$/, '').replace(/\s+/g, '').toUpperCase();
|
|
12
|
+
const bits = [];
|
|
13
|
+
for (const ch of clean) {
|
|
14
|
+
const idx = BASE32_ALPHABET.indexOf(ch);
|
|
15
|
+
if (idx === -1)
|
|
16
|
+
throw new Error(`Invalid base32 character: ${ch}`);
|
|
17
|
+
for (let i = 4; i >= 0; i--)
|
|
18
|
+
bits.push((idx >> i) & 1);
|
|
19
|
+
}
|
|
20
|
+
const bytes = [];
|
|
21
|
+
for (let i = 0; i + 8 <= bits.length; i += 8) {
|
|
22
|
+
let byte = 0;
|
|
23
|
+
for (let j = 0; j < 8; j++)
|
|
24
|
+
byte = (byte << 1) | bits[i + j];
|
|
25
|
+
bytes.push(byte);
|
|
26
|
+
}
|
|
27
|
+
return Buffer.from(bytes);
|
|
28
|
+
}
|
|
29
|
+
export function code(secretBase32, timeMs = Date.now(), stepSec = 30, digits = 6) {
|
|
30
|
+
const key = base32Decode(secretBase32);
|
|
31
|
+
const counter = Math.floor(timeMs / 1000 / stepSec);
|
|
32
|
+
const buf = Buffer.alloc(8);
|
|
33
|
+
buf.writeBigUInt64BE(BigInt(counter), 0);
|
|
34
|
+
const hmac = createHmac('sha1', key).update(buf).digest();
|
|
35
|
+
const offset = hmac[hmac.length - 1] & 0x0f;
|
|
36
|
+
const value = (((hmac[offset] & 0x7f) << 24) |
|
|
37
|
+
((hmac[offset + 1] & 0xff) << 16) |
|
|
38
|
+
((hmac[offset + 2] & 0xff) << 8) |
|
|
39
|
+
(hmac[offset + 3] & 0xff));
|
|
40
|
+
const mod = 10 ** digits;
|
|
41
|
+
return String(value % mod).padStart(digits, '0');
|
|
42
|
+
}
|
|
43
|
+
export function secondsUntilNextCode(timeMs = Date.now(), stepSec = 30) {
|
|
44
|
+
return stepSec - Math.floor(timeMs / 1000) % stepSec;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=totp.js.map
|
package/dist/totp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"totp.js","sourceRoot":"","sources":["../totp.ts"],"names":[],"mappings":"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"}
|