mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
6e764e3c49
* 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
101 lines
3 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
);
|
|
}
|