mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-03 02:53:40 +00:00
7d2335ed07
To prevent potential SSRF attempts, we can ignore a misconfigured/malicious `next` link, and log a warning. Co-authored-by: Claude Opus 4.8 <jamie.tanna+claude-code@mend.io>
93 lines
3.3 KiB
TypeScript
93 lines
3.3 KiB
TypeScript
import type { XmlElement } from 'xmldoc';
|
|
import { XmlDocument } from 'xmldoc';
|
|
import { logger } from '../../../logger/index.ts';
|
|
import type { Http } from '../../../util/http/index.ts';
|
|
import { regEx } from '../../../util/regex.ts';
|
|
import { asTimestamp } from '../../../util/timestamp.ts';
|
|
import type { ReleaseResult } from '../types.ts';
|
|
import { resolvePaginationUrl } from '../util.ts';
|
|
import { massageUrl, removeBuildMeta } from './common.ts';
|
|
|
|
export class NugetV2Api {
|
|
getPkgProp(pkgInfo: XmlElement, propName: string): string | undefined {
|
|
return pkgInfo.childNamed('m:properties')?.childNamed(`d:${propName}`)?.val;
|
|
}
|
|
|
|
async getReleases(
|
|
http: Http,
|
|
feedUrl: string,
|
|
pkgName: string,
|
|
allowCrossOrigin: boolean,
|
|
): Promise<ReleaseResult | null> {
|
|
const dep: ReleaseResult = {
|
|
releases: [],
|
|
};
|
|
let pkgUrlList: string | null = `${feedUrl.replace(
|
|
regEx(/\/+$/),
|
|
'',
|
|
)}/FindPackagesById()?id=%27${pkgName}%27&$select=Version,IsLatestVersion,ProjectUrl,Published`;
|
|
while (pkgUrlList !== null) {
|
|
// typescript issue
|
|
const pkgVersionsListRaw = await http.getText(pkgUrlList);
|
|
const pkgVersionsListDoc = new XmlDocument(pkgVersionsListRaw.body);
|
|
|
|
const pkgInfoList = pkgVersionsListDoc.childrenNamed('entry');
|
|
|
|
for (const pkgInfo of pkgInfoList) {
|
|
const version = this.getPkgProp(pkgInfo, 'Version');
|
|
const releaseTimestamp = asTimestamp(
|
|
this.getPkgProp(pkgInfo, 'Published'),
|
|
);
|
|
dep.releases.push({
|
|
// TODO: types (#22198)
|
|
version: removeBuildMeta(`${version}`),
|
|
releaseTimestamp,
|
|
});
|
|
try {
|
|
const pkgIsLatestVersion = this.getPkgProp(
|
|
pkgInfo,
|
|
'IsLatestVersion',
|
|
);
|
|
if (pkgIsLatestVersion === 'true') {
|
|
dep.tags = { latest: removeBuildMeta(`${version}`) };
|
|
const projectUrl = this.getPkgProp(pkgInfo, 'ProjectUrl');
|
|
if (projectUrl) {
|
|
dep.sourceUrl = massageUrl(projectUrl);
|
|
}
|
|
}
|
|
} catch (err) /* istanbul ignore next */ {
|
|
logger.debug(
|
|
{ err, pkgName, feedUrl },
|
|
`nuget registry failure: can't parse pkg info for project url`,
|
|
);
|
|
}
|
|
}
|
|
|
|
const nextPkgUrlListLink = pkgVersionsListDoc
|
|
.childrenNamed('link')
|
|
.find((node) => node.attr.rel === 'next');
|
|
|
|
// Resolve the relative-or-absolute next link, but only follow it when it stays on the same origin, or if the user has opted in via `RENOVATE_X_NUGET_PAGINATION_ALLOW_CROSS_ORIGIN`
|
|
const nextHref = nextPkgUrlListLink?.attr.href;
|
|
const nextUrl: string | null = nextHref
|
|
? resolvePaginationUrl(pkgUrlList, nextHref, allowCrossOrigin)
|
|
: null;
|
|
if (nextHref && !nextUrl) {
|
|
// make sure that users are aware if there are any (potentially malicious, or misconfigured) pagination links being returned
|
|
logger.once.warn(
|
|
{ feedUrl, nextUrl: nextHref },
|
|
'Ignoring cross-origin or invalid NuGet feed pagination link',
|
|
);
|
|
}
|
|
pkgUrlList = nextUrl;
|
|
}
|
|
|
|
// dep not found if no release, so we can try next registry
|
|
if (dep.releases.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return dep;
|
|
}
|
|
}
|