UNPKG

@nodesecure/scanner

Version:

A package API to run a static analysis of your module's dependencies.

127 lines 5.1 kB
// Import Third-party Dependencies import semver from "semver"; import * as npmRegistrySDK from "@nodesecure/npm-registry-sdk"; import { packageJSONIntegrityHash } from "@nodesecure/mama"; // Import Internal Dependencies import { getLinks } from "./utils/index.js"; import { Logger } from "./class/logger.class.js"; export async function manifestMetadata(name, version, dependency) { try { const pkgVersion = await npmRegistrySDK.packumentVersion(name, version); const integrity = packageJSONIntegrityHash(pkgVersion, { isFromRemoteRegistry: true }); Object.assign(dependency.versions[version], { links: getLinks(pkgVersion) }); dependency.metadata.integrity[version] = integrity; } catch { // Ignore } } export async function packageMetadata(name, version, options) { const { dependency, logger } = options; const spec = `${name}:${version}`; try { const pkg = await npmRegistrySDK.packument(name); const oneYearFromToday = new Date(); oneYearFromToday.setFullYear(oneYearFromToday.getFullYear() - 1); const lastVersion = pkg["dist-tags"].latest; const lastUpdateAt = new Date(pkg.time[lastVersion]); const metadata = { author: pkg.author ?? null, homepage: pkg.homepage || null, publishedCount: Object.values(pkg.versions).length, lastVersion, lastUpdateAt, hasReceivedUpdateInOneYear: !(oneYearFromToday > lastUpdateAt), hasManyPublishers: false, hasChangedAuthor: false, maintainers: pkg.maintainers ?? [], publishers: [], integrity: {} }; const isOutdated = semver.neq(version, lastVersion); const dependencyVersion = dependency.versions[version]; const flags = dependencyVersion.flags; if (isOutdated) { flags.push("isOutdated"); } const publishers = new Set(); let searchForMaintainersInVersions = metadata.maintainers.length === 0; for (const ver of Object.values(pkg.versions).reverse()) { if (spec === `${ver.name}:${ver.version}`) { if ("deprecated" in ver && !flags.includes("isDeprecated")) { flags.push("isDeprecated"); dependencyVersion.deprecated = ver.deprecated; } metadata.integrity[ver.version] = packageJSONIntegrityHash(ver, { isFromRemoteRegistry: true }); } const { _npmUser = null, version, maintainers = [] } = ver; if (_npmUser !== null) { const authorName = metadata.author?.name ?? null; if (authorName === null) { metadata.author = _npmUser; } else if (authorName !== null && _npmUser.name !== authorName) { metadata.hasManyPublishers = true; } if (!publishers.has(_npmUser.name)) { publishers.add(_npmUser.name); metadata.publishers.push({ ..._npmUser, version, at: new Date(pkg.time[version]).toISOString() }); } } if (searchForMaintainersInVersions) { metadata.maintainers.push(...maintainers); searchForMaintainersInVersions = false; } } await addNpmAvatar(metadata); Object.assign(dependency.versions[version], { links: getLinks(pkg.versions[version]) }); dependency.metadata = metadata; } catch { // ignore } finally { logger.tick("registry"); } } async function addNpmAvatar(metadata) { const contributors = [ ...metadata.maintainers, ...metadata.publishers ]; if (metadata.author !== null) { contributors.push(metadata.author); } const emailToAvatar = {}; const promises = contributors.map((contributor) => { if (contributor.email && emailToAvatar[contributor.email]) { contributor.npmAvatar = emailToAvatar[contributor.email]; return Promise.resolve(); } return npmRegistrySDK.user(contributor.name, { perPage: 1 }) .then((profile) => { contributor.npmAvatar = profile.avatars.small; if (contributor.email && contributor.npmAvatar) { emailToAvatar[contributor.email] = contributor.npmAvatar; } }).catch(() => { contributor.npmAvatar = undefined; }); }); await Promise.all(promises); // back fill npmAvatar if any name property was not npm username in first pass for (const contributor of contributors) { if (!contributor.npmAvatar && contributor.email && emailToAvatar[contributor.email]) { contributor.npmAvatar = emailToAvatar[contributor.email]; } } } //# sourceMappingURL=npmRegistry.js.map