0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-16 21:56:25 -05:00
verdaccio/packages/api/src/package.ts
Marc Bernard 6e764e3c49
feat: add support for npm owner (#4582)
* feat: add support for npm owner

* Revert debug msg

* Finish feature and add test cases

* Fix remote user name and more tests

* Simplify passing remote user

* Update version metadata with owners

* Add test for validateUserName

* Add comment for "change owner"

* add config option

* add check to removePackage, removeTarball

* typo

* check access when write=true

* Add to config, fix undefined user

* Update docs

* Update docs

* Update readme
2024-06-13 12:06:01 +02:00

101 lines
3 KiB
TypeScript

import buildDebug from 'debug';
import { Router } from 'express';
import { Auth } from '@verdaccio/auth';
import { HEADERS, HEADER_TYPE, stringUtils } from '@verdaccio/core';
import { logger } from '@verdaccio/logger';
import { allow } from '@verdaccio/middleware';
import { Storage } from '@verdaccio/store';
import { $NextFunctionVer, $RequestExtend, $ResponseExtend } from '../types/custom';
const debug = buildDebug('verdaccio:api:package');
export default function (route: Router, auth: Auth, storage: Storage): void {
const can = allow(auth, {
beforeAll: (a, b) => logger.trace(a, b),
afterAll: (a, b) => logger.trace(a, b),
});
route.get(
'/:package/:version?',
can('access'),
async function (
req: $RequestExtend,
_res: $ResponseExtend,
next: $NextFunctionVer
): Promise<void> {
debug('init package by version');
const name = req.params.package;
let version = req.params.version;
const write = req.query.write === 'true';
const username = req?.remote_user?.name;
const abbreviated =
stringUtils.getByQualityPriorityValue(req.get('Accept')) === Storage.ABBREVIATED_HEADER;
const requestOptions = {
protocol: req.protocol,
headers: req.headers as any,
// FIXME: if we migrate to req.hostname, the port is not longer included.
host: req.host,
remoteAddress: req.socket.remoteAddress,
byPassCache: write,
username,
};
try {
const manifest = await storage.getPackageByOptions({
name,
uplinksLook: true,
abbreviated,
version,
requestOptions,
});
if (abbreviated) {
_res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON_INSTALL_CHARSET);
} else {
_res.setHeader(HEADER_TYPE.CONTENT_TYPE, HEADERS.JSON);
}
next(manifest);
} catch (err) {
next(err);
}
}
);
route.get(
'/:package/-/:filename',
can('access'),
async function (req: $RequestExtend, res: $ResponseExtend, next): Promise<void> {
const { package: pkgName, filename } = req.params;
const abort = new AbortController();
try {
const stream = (await storage.getTarball(pkgName, filename, {
signal: abort.signal,
// TODO: review why this param
// enableRemote: true,
})) as any;
stream.on('content-length', (size) => {
res.header(HEADER_TYPE.CONTENT_LENGTH, size);
});
stream.once('error', (err) => {
res.locals.report_error(err);
next(err);
});
req.on('abort', () => {
debug('request aborted for %o', req.url);
abort.abort();
});
res.header(HEADERS.CONTENT_TYPE, HEADERS.OCTET_STREAM);
stream.pipe(res);
} catch (err: any) {
// console.log('catch API error request', err);
res.locals.report_error(err);
next(err);
}
}
);
}