mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-20 17:05:52 +01:00
feat: remove level dependency by lowdb for npm token cli as storage (#2043)
* feat: remove level for token by lowdb * chore: fix format * chore: fix config * chore: add changeset
This commit is contained in:
parent
c3565f7157
commit
e54ec4b5d0
20
.changeset/late-adults-love.md
Normal file
20
.changeset/late-adults-love.md
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
'@verdaccio/api': minor
|
||||
'verdaccio-htpasswd': minor
|
||||
'@verdaccio/local-storage': minor
|
||||
---
|
||||
|
||||
feat: remove level dependency by lowdb for npm token cli as storage
|
||||
|
||||
### new npm token database
|
||||
|
||||
There will be a new database located in your storage named `.token-db.json` which
|
||||
will store all references to created tokens, **it does not store tokens**, just
|
||||
mask of them and related metadata required to reference them.
|
||||
|
||||
#### Breaking change
|
||||
|
||||
If you were relying on `npm token` experiment. This PR will replace the
|
||||
used database (level) by a json plain based one (lowbd) which does not
|
||||
require Node.js C++ compilation step and has less dependencies. Since was
|
||||
a experiment there is no migration step.
|
@ -50,6 +50,7 @@
|
||||
"@types/jest": "^26.0.19",
|
||||
"@types/lodash": "4.14.165",
|
||||
"@types/mime": "2.0.2",
|
||||
"@types/lowdb": "^1.0.9",
|
||||
"@types/minimatch": "3.0.3",
|
||||
"@types/node": "^14.14.7",
|
||||
"@types/semver": "7.2.0",
|
||||
|
@ -65,11 +65,11 @@ export default function (
|
||||
ping(app);
|
||||
stars(app, storage);
|
||||
|
||||
if (_.get(config, 'experiments.search') === true) {
|
||||
if (config?.flags?.search === true) {
|
||||
v1Search(app, auth, storage);
|
||||
}
|
||||
|
||||
if (_.get(config, 'experiments.token') === true) {
|
||||
if (config?.flags?.token === true) {
|
||||
token(app, auth, storage, config);
|
||||
}
|
||||
return app;
|
||||
|
@ -106,6 +106,8 @@ export const API_ERROR = {
|
||||
VERSION_NOT_EXIST: "this version doesn't exist",
|
||||
UNSUPORTED_REGISTRY_CALL: 'unsupported registry call',
|
||||
FILE_NOT_FOUND: 'File not found',
|
||||
REGISTRATION_DISABLED: 'user registration disabled',
|
||||
UNAUTHORIZED_ACCESS: 'unauthorized access',
|
||||
BAD_STATUS_CODE: 'bad status code',
|
||||
PACKAGE_EXIST: 'this package is already present',
|
||||
BAD_AUTH_HEADER: 'bad authorization header',
|
||||
|
@ -28,6 +28,7 @@
|
||||
"node": ">=10"
|
||||
},
|
||||
"dependencies": {
|
||||
"@verdaccio/commons-api": "workspace:10.0.0-alpha.1",
|
||||
"@verdaccio/file-locking": "workspace:10.0.0-alpha.1",
|
||||
"apache-md5": "1.1.2",
|
||||
"bcryptjs": "2.4.3",
|
||||
|
@ -5,6 +5,7 @@ import bcrypt from 'bcryptjs';
|
||||
import createError, { HttpError } from 'http-errors';
|
||||
import { readFile } from '@verdaccio/file-locking';
|
||||
import { Callback } from '@verdaccio/types';
|
||||
import { API_ERROR, HTTP_STATUS } from '@verdaccio/commons-api';
|
||||
|
||||
import crypt3 from './crypt3';
|
||||
|
||||
@ -70,7 +71,7 @@ export function addUserToHTPasswd(body: string, user: string, passwd: string): s
|
||||
if (user !== encodeURIComponent(user)) {
|
||||
const err = createError('username should not contain non-uri-safe characters');
|
||||
|
||||
err.status = 409;
|
||||
err.status = HTTP_STATUS.CONFLICT;
|
||||
throw err;
|
||||
}
|
||||
|
||||
@ -106,32 +107,32 @@ export function sanityCheck(
|
||||
|
||||
// check for user or password
|
||||
if (!user || !password) {
|
||||
err = Error('username and password is required');
|
||||
err.status = 400;
|
||||
err = Error(API_ERROR.USERNAME_PASSWORD_REQUIRED);
|
||||
err.status = HTTP_STATUS.BAD_REQUEST;
|
||||
return err;
|
||||
}
|
||||
|
||||
const hash = users[user];
|
||||
|
||||
if (maxUsers < 0) {
|
||||
err = Error('user registration disabled');
|
||||
err.status = 409;
|
||||
err = Error(API_ERROR.REGISTRATION_DISABLED);
|
||||
err.status = HTTP_STATUS.CONFLICT;
|
||||
return err;
|
||||
}
|
||||
|
||||
if (hash) {
|
||||
const auth = verifyFn(password, users[user]);
|
||||
if (auth) {
|
||||
err = Error('username is already registered');
|
||||
err.status = 409;
|
||||
err = Error(API_ERROR.USERNAME_ALREADY_REGISTERED);
|
||||
err.status = HTTP_STATUS.CONFLICT;
|
||||
return err;
|
||||
}
|
||||
err = Error('unauthorized access');
|
||||
err.status = 401;
|
||||
err = Error(API_ERROR.UNAUTHORIZED_ACCESS);
|
||||
err.status = HTTP_STATUS.UNAUTHORIZED;
|
||||
return err;
|
||||
} else if (Object.keys(users).length >= maxUsers) {
|
||||
err = Error('maximum amount of users reached');
|
||||
err.status = 403;
|
||||
err = Error(API_ERROR.MAX_USERS_REACHED);
|
||||
err.status = HTTP_STATUS.FORBIDDEN;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,9 @@
|
||||
"references": [
|
||||
{
|
||||
"path": "../file-locking"
|
||||
},
|
||||
{
|
||||
"path": "../commons-api"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -36,9 +36,9 @@
|
||||
"@verdaccio/streams": "workspace:10.0.0-alpha.1",
|
||||
"async": "^3.2.0",
|
||||
"debug": "^4.1.1",
|
||||
"level": "5.0.1",
|
||||
"lodash": "^4.17.20",
|
||||
"mkdirp": "^0.5.5"
|
||||
"mkdirp": "^0.5.5",
|
||||
"lowdb": "1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/minimatch": "^3.0.3",
|
||||
|
@ -1,6 +1,5 @@
|
||||
import fs from 'fs';
|
||||
import Path from 'path';
|
||||
import stream from 'stream';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
import _ from 'lodash';
|
||||
@ -14,47 +13,27 @@ import {
|
||||
LocalStorage,
|
||||
Logger,
|
||||
StorageList,
|
||||
Token,
|
||||
TokenFilter,
|
||||
} from '@verdaccio/types';
|
||||
import level from 'level';
|
||||
import { getInternalError } from '@verdaccio/commons-api';
|
||||
|
||||
import LocalDriver, { noSuchFile } from './local-fs';
|
||||
import { loadPrivatePackages } from './pkg-utils';
|
||||
import TokenActions from './token';
|
||||
|
||||
const DEPRECATED_DB_NAME = '.sinopia-db.json';
|
||||
const DB_NAME = '.verdaccio-db.json';
|
||||
const TOKEN_DB_NAME = '.token-db';
|
||||
|
||||
interface Level {
|
||||
put(key: string, token, fn?: Function): void;
|
||||
|
||||
get(key: string, fn?: Function): void;
|
||||
|
||||
del(key: string, fn?: Function): void;
|
||||
|
||||
createReadStream(options?: object): stream.Readable;
|
||||
}
|
||||
|
||||
const debug = buildDebug('verdaccio:plugin:local-storage');
|
||||
|
||||
/**
|
||||
* Handle local database.
|
||||
*/
|
||||
class LocalDatabase implements IPluginStorage<{}> {
|
||||
class LocalDatabase extends TokenActions implements IPluginStorage<{}> {
|
||||
public path: string;
|
||||
public logger: Logger;
|
||||
public data: LocalStorage;
|
||||
public config: Config;
|
||||
public locked: boolean;
|
||||
public tokenDb;
|
||||
|
||||
/**
|
||||
* Load an parse the local json database.
|
||||
* @param {*} path the database path
|
||||
*/
|
||||
public constructor(config: Config, logger: Logger) {
|
||||
super(config);
|
||||
this.config = config;
|
||||
this.path = this._buildStoragePath(config);
|
||||
this.logger = logger;
|
||||
@ -75,11 +54,6 @@ class LocalDatabase implements IPluginStorage<{}> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new element.
|
||||
* @param {*} name
|
||||
* @return {Error|*}
|
||||
*/
|
||||
public add(name: string, cb: Callback): void {
|
||||
if (this.data.list.indexOf(name) === -1) {
|
||||
this.data.list.push(name);
|
||||
@ -169,7 +143,7 @@ class LocalDatabase implements IPluginStorage<{}> {
|
||||
{
|
||||
name: file,
|
||||
path: packagePath,
|
||||
time: self._getTime(stats.mtime.getTime(), stats.mtime),
|
||||
time: self.getTime(stats.mtime.getTime(), stats.mtime),
|
||||
},
|
||||
cb
|
||||
);
|
||||
@ -187,11 +161,6 @@ class LocalDatabase implements IPluginStorage<{}> {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an element from the database.
|
||||
* @param {*} name
|
||||
* @return {Error|*}
|
||||
*/
|
||||
public remove(name: string, cb: Callback): void {
|
||||
this.get((err, data) => {
|
||||
if (err) {
|
||||
@ -254,56 +223,7 @@ class LocalDatabase implements IPluginStorage<{}> {
|
||||
this._sync();
|
||||
}
|
||||
|
||||
public saveToken(token: Token): Promise<void> {
|
||||
const key = this._getTokenKey(token);
|
||||
const db = this.getTokenDb();
|
||||
|
||||
return new Promise((resolve, reject): void => {
|
||||
db.put(key, token, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public deleteToken(user: string, tokenKey: string): Promise<void> {
|
||||
const key = this._compoundTokenKey(user, tokenKey);
|
||||
const db = this.getTokenDb();
|
||||
return new Promise((resolve, reject): void => {
|
||||
db.del(key, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public readTokens(filter: TokenFilter): Promise<Token[]> {
|
||||
return new Promise((resolve, reject): void => {
|
||||
const tokens: Token[] = [];
|
||||
const key = filter.user + ':';
|
||||
const db = this.getTokenDb();
|
||||
const stream = db.createReadStream({
|
||||
gte: key,
|
||||
lte: String.fromCharCode(key.charCodeAt(0) + 1),
|
||||
});
|
||||
|
||||
stream.on('data', (data) => {
|
||||
tokens.push(data.value);
|
||||
});
|
||||
|
||||
stream.once('end', () => resolve(tokens));
|
||||
|
||||
stream.once('error', (err) => reject(err));
|
||||
});
|
||||
}
|
||||
|
||||
private _getTime(time: number, mtime: Date): number | Date {
|
||||
private getTime(time: number, mtime: Date): number | Date {
|
||||
return time ? time : mtime;
|
||||
}
|
||||
|
||||
@ -410,12 +330,6 @@ class LocalDatabase implements IPluginStorage<{}> {
|
||||
}
|
||||
}
|
||||
|
||||
private _dbGenPath(dbName: string, config: Config): string {
|
||||
return Path.join(
|
||||
Path.resolve(Path.dirname(config.config_path || ''), config.storage as string, dbName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch local packages.
|
||||
* @private
|
||||
@ -426,9 +340,7 @@ class LocalDatabase implements IPluginStorage<{}> {
|
||||
const emptyDatabase = { list, secret: '' };
|
||||
|
||||
try {
|
||||
const db = loadPrivatePackages(this.path, this.logger);
|
||||
|
||||
return db;
|
||||
return loadPrivatePackages(this.path, this.logger);
|
||||
} catch (err) {
|
||||
// readFileSync is platform specific, macOS, Linux and Windows thrown an error
|
||||
// Only recreate if file not found to prevent data loss
|
||||
@ -443,25 +355,6 @@ class LocalDatabase implements IPluginStorage<{}> {
|
||||
return emptyDatabase;
|
||||
}
|
||||
}
|
||||
|
||||
private getTokenDb(): Level {
|
||||
if (!this.tokenDb) {
|
||||
this.tokenDb = level(this._dbGenPath(TOKEN_DB_NAME, this.config), {
|
||||
valueEncoding: 'json',
|
||||
});
|
||||
}
|
||||
|
||||
return this.tokenDb;
|
||||
}
|
||||
|
||||
private _getTokenKey(token: Token): string {
|
||||
const { user, key } = token;
|
||||
return this._compoundTokenKey(user, key);
|
||||
}
|
||||
|
||||
private _compoundTokenKey(user: string, key: string): string {
|
||||
return `${user}:${key}`;
|
||||
}
|
||||
}
|
||||
|
||||
export default LocalDatabase;
|
||||
|
87
packages/core/local-storage/src/token.ts
Normal file
87
packages/core/local-storage/src/token.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import Path from 'path';
|
||||
import _ from 'lodash';
|
||||
import low from 'lowdb';
|
||||
import FileAsync from 'lowdb/adapters/FileAsync';
|
||||
import FileMemory from 'lowdb/adapters/Memory';
|
||||
import buildDebug from 'debug';
|
||||
|
||||
import { ITokenActions, Config, Token, TokenFilter } from '@verdaccio/types';
|
||||
|
||||
const debug = buildDebug('verdaccio:plugin:local-storage:token');
|
||||
|
||||
const TOKEN_DB_NAME = '.token-db.json';
|
||||
|
||||
export default class TokenActions implements ITokenActions {
|
||||
public config: Config;
|
||||
public tokenDb: low.LowdbAsync<any> | null;
|
||||
|
||||
public constructor(config: Config) {
|
||||
this.config = config;
|
||||
this.tokenDb = null;
|
||||
}
|
||||
|
||||
public _dbGenPath(dbName: string, config: Config): string {
|
||||
return Path.join(
|
||||
Path.resolve(Path.dirname(config.config_path || ''), config.storage as string, dbName)
|
||||
);
|
||||
}
|
||||
|
||||
private async getTokenDb(): Promise<low.LowdbAsync<any>> {
|
||||
if (!this.tokenDb) {
|
||||
debug('token database is not defined');
|
||||
let adapter;
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
debug('token memory adapter');
|
||||
adapter = new FileMemory('');
|
||||
} else {
|
||||
debug('token async adapter');
|
||||
const pathDb = this._dbGenPath(TOKEN_DB_NAME, this.config);
|
||||
adapter = new FileAsync(pathDb);
|
||||
}
|
||||
debug('token bd generated');
|
||||
this.tokenDb = await low(adapter);
|
||||
}
|
||||
|
||||
return this.tokenDb;
|
||||
}
|
||||
|
||||
public async saveToken(token: Token): Promise<void> {
|
||||
debug('token key %o', token.key);
|
||||
const db = await this.getTokenDb();
|
||||
const userData = await db.get(token.user).value();
|
||||
debug('user data %o', userData);
|
||||
if (_.isNil(userData)) {
|
||||
await db.set(token.user, [token]).write();
|
||||
debug('token user %o new database', token.user);
|
||||
} else {
|
||||
// types does not match with valid implementation
|
||||
// @ts-ignore
|
||||
await db.get(token.user).push(token).write();
|
||||
}
|
||||
debug('data %o', await db.getState());
|
||||
debug('token saved %o', token.user);
|
||||
}
|
||||
|
||||
public async deleteToken(user: string, tokenKey: string): Promise<void> {
|
||||
const db = await this.getTokenDb();
|
||||
const userTokens = await db.get(user).value();
|
||||
if (_.isNil(userTokens)) {
|
||||
throw new Error('user not found');
|
||||
}
|
||||
debug('tokens %o - %o', userTokens, userTokens.length);
|
||||
const remainingTokens = userTokens.filter(({ key }) => {
|
||||
debug('key %o', key);
|
||||
return key !== tokenKey;
|
||||
});
|
||||
await db.set(user, remainingTokens).write();
|
||||
debug('removed tokens key %o', tokenKey);
|
||||
}
|
||||
|
||||
public async readTokens(filter: TokenFilter): Promise<Token[]> {
|
||||
const { user } = filter;
|
||||
debug('read tokens with %o', user);
|
||||
const db = await this.getTokenDb();
|
||||
const tokens = await db.get(user).value();
|
||||
return tokens || [];
|
||||
}
|
||||
}
|
@ -218,86 +218,4 @@ describe('Local Database', () => {
|
||||
spyInstance.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('token', () => {
|
||||
let token: Token;
|
||||
|
||||
beforeEach(() => {
|
||||
(locaDatabase as LocalDatabase).tokenDb = {
|
||||
put: jest.fn().mockImplementation((key, value, cb) => cb()),
|
||||
del: jest.fn().mockImplementation((key, cb) => cb()),
|
||||
createReadStream: jest.fn(),
|
||||
};
|
||||
|
||||
token = {
|
||||
user: 'someUser',
|
||||
viewToken: 'viewToken',
|
||||
key: 'someHash',
|
||||
readonly: true,
|
||||
createdTimestamp: new Date().getTime(),
|
||||
};
|
||||
});
|
||||
|
||||
test('should save token', async (done) => {
|
||||
const db = (locaDatabase as LocalDatabase).tokenDb;
|
||||
|
||||
await locaDatabase.saveToken(token);
|
||||
|
||||
expect(db.put).toHaveBeenCalledWith('someUser:someHash', token, expect.anything());
|
||||
done();
|
||||
});
|
||||
|
||||
test('should delete token', async (done) => {
|
||||
const db = (locaDatabase as LocalDatabase).tokenDb;
|
||||
|
||||
await locaDatabase.deleteToken('someUser', 'someHash');
|
||||
|
||||
expect(db.del).toHaveBeenCalledWith('someUser:someHash', expect.anything());
|
||||
done();
|
||||
});
|
||||
|
||||
test('should get tokens', async () => {
|
||||
const db = (locaDatabase as LocalDatabase).tokenDb;
|
||||
const events = { on: {}, once: {} };
|
||||
const stream = {
|
||||
on: (event, cb): void => {
|
||||
events.on[event] = cb;
|
||||
},
|
||||
once: (event, cb): void => {
|
||||
events.once[event] = cb;
|
||||
},
|
||||
};
|
||||
db.createReadStream.mockImplementation(() => stream);
|
||||
setTimeout(() => events.on['data']({ value: token }));
|
||||
setTimeout(() => events.once['end']());
|
||||
|
||||
const tokens = await locaDatabase.readTokens({ user: 'someUser' });
|
||||
|
||||
expect(db.createReadStream).toHaveBeenCalledWith({
|
||||
gte: 'someUser:',
|
||||
lte: 't',
|
||||
});
|
||||
expect(tokens).toHaveLength(1);
|
||||
expect(tokens[0]).toBe(token);
|
||||
});
|
||||
|
||||
test('should fail getting tokens if something goes wrong', async () => {
|
||||
const db = (locaDatabase as LocalDatabase).tokenDb;
|
||||
const events = { on: {}, once: {} };
|
||||
const stream = {
|
||||
on: (event, cb): void => {
|
||||
events.on[event] = cb;
|
||||
},
|
||||
once: (event, cb): void => {
|
||||
events.once[event] = cb;
|
||||
},
|
||||
};
|
||||
db.createReadStream.mockImplementation(() => stream);
|
||||
setTimeout(() => events.once['error'](new Error('Unexpected error!')));
|
||||
|
||||
await expect(locaDatabase.readTokens({ user: 'someUser' })).rejects.toThrow(
|
||||
'Unexpected error!'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
81
packages/core/local-storage/tests/token.test.ts
Normal file
81
packages/core/local-storage/tests/token.test.ts
Normal file
@ -0,0 +1,81 @@
|
||||
/* eslint-disable jest/no-mocks-import */
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { assign } from 'lodash';
|
||||
import { ILocalData, PluginOptions, Token } from '@verdaccio/types';
|
||||
|
||||
import LocalDatabase from '../src/local-database';
|
||||
import { ILocalFSPackageManager } from '../src/local-fs';
|
||||
import * as pkgUtils from '../src/pkg-utils';
|
||||
|
||||
// FIXME: remove this mocks imports
|
||||
import Config from './__mocks__/Config';
|
||||
import logger from './__mocks__/Logger';
|
||||
|
||||
const optionsPlugin: PluginOptions<{}> = {
|
||||
logger,
|
||||
config: new Config(),
|
||||
};
|
||||
|
||||
let locaDatabase: ILocalData<{}>;
|
||||
let loadPrivatePackages;
|
||||
|
||||
describe('Local Database', () => {
|
||||
beforeEach(() => {
|
||||
const writeMock = jest.spyOn(fs, 'writeFileSync').mockImplementation();
|
||||
loadPrivatePackages = jest
|
||||
.spyOn(pkgUtils, 'loadPrivatePackages')
|
||||
.mockReturnValue({ list: [], secret: '' });
|
||||
locaDatabase = new LocalDatabase(optionsPlugin.config, optionsPlugin.logger);
|
||||
(locaDatabase as LocalDatabase).clean();
|
||||
writeMock.mockClear();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('token', () => {
|
||||
let token: Token = {
|
||||
user: 'someUser',
|
||||
viewToken: 'viewToken',
|
||||
key: 'someHash',
|
||||
readonly: true,
|
||||
createdTimestamp: new Date().getTime(),
|
||||
};
|
||||
|
||||
test('should save and get token', async () => {
|
||||
await locaDatabase.saveToken(token);
|
||||
const tokens = await locaDatabase.readTokens({ user: token.user });
|
||||
expect(tokens).toHaveLength(1);
|
||||
expect(tokens[0]).toEqual(token);
|
||||
});
|
||||
|
||||
test('should revoke and get token', async () => {
|
||||
await locaDatabase.saveToken(token);
|
||||
const tokens = await locaDatabase.readTokens({ user: token.user });
|
||||
expect(tokens).toHaveLength(1);
|
||||
expect(tokens[0]).toEqual(token);
|
||||
await locaDatabase.deleteToken(token.user, token.key);
|
||||
const tokens2 = await locaDatabase.readTokens({ user: token.user });
|
||||
expect(tokens2).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('should fail on revoke', async () => {
|
||||
await expect(locaDatabase.deleteToken({ user: 'foo', key: 'bar' })).rejects.toThrow(
|
||||
'user not found'
|
||||
);
|
||||
});
|
||||
|
||||
test('should verify save more than one token', async () => {
|
||||
await locaDatabase.saveToken(token);
|
||||
const tokens = await locaDatabase.readTokens({ user: token.user });
|
||||
expect(tokens).toHaveLength(1);
|
||||
expect(tokens[0]).toEqual(token);
|
||||
await locaDatabase.saveToken({ ...token, key: 'foo' });
|
||||
expect(tokens).toHaveLength(2);
|
||||
expect(tokens[1].key).toEqual('foo');
|
||||
});
|
||||
});
|
||||
});
|
2
packages/core/types/index.d.ts
vendored
2
packages/core/types/index.d.ts
vendored
@ -381,7 +381,7 @@ declare module '@verdaccio/types' {
|
||||
https: HttpsConf;
|
||||
}
|
||||
|
||||
interface ITokenActions {
|
||||
export interface ITokenActions {
|
||||
saveToken(token: Token): Promise<any>;
|
||||
deleteToken(user: string, tokenKey: string): Promise<any>;
|
||||
readTokens(filter: TokenFilter): Promise<Token[]>;
|
||||
|
@ -22,6 +22,6 @@ packages:
|
||||
publish: $authenticated
|
||||
logs:
|
||||
- { type: stdout, format: pretty, level: error }
|
||||
experiments:
|
||||
flags:
|
||||
## enable token for testing
|
||||
token: true
|
||||
|
54
pnpm-lock.yaml
generated
54
pnpm-lock.yaml
generated
@ -38,6 +38,7 @@ importers:
|
||||
'@types/jest': 26.0.19
|
||||
'@types/js-base64': 3.0.0
|
||||
'@types/lodash': 4.14.165
|
||||
'@types/lowdb': 1.0.9
|
||||
'@types/mime': 2.0.2
|
||||
'@types/minimatch': 3.0.3
|
||||
'@types/node': 14.14.7
|
||||
@ -143,6 +144,7 @@ importers:
|
||||
'@types/jest': ^26.0.19
|
||||
'@types/js-base64': 3.0.0
|
||||
'@types/lodash': 4.14.165
|
||||
'@types/lowdb': ^1.0.9
|
||||
'@types/mime': 2.0.2
|
||||
'@types/minimatch': 3.0.3
|
||||
'@types/node': ^14.14.7
|
||||
@ -336,6 +338,7 @@ importers:
|
||||
lockfile: 1.0.4
|
||||
packages/core/htpasswd:
|
||||
dependencies:
|
||||
'@verdaccio/commons-api': 'link:../commons-api'
|
||||
'@verdaccio/file-locking': 'link:../file-locking'
|
||||
apache-md5: 1.1.2
|
||||
bcryptjs: 2.4.3
|
||||
@ -346,6 +349,7 @@ importers:
|
||||
'@verdaccio/types': 'link:../types'
|
||||
specifiers:
|
||||
'@types/bcryptjs': ^2.4.2
|
||||
'@verdaccio/commons-api': 'workspace:10.0.0-alpha.1'
|
||||
'@verdaccio/file-locking': 'workspace:10.0.0-alpha.1'
|
||||
'@verdaccio/types': 'workspace:10.0.0-alpha.1'
|
||||
apache-md5: 1.1.2
|
||||
@ -359,8 +363,8 @@ importers:
|
||||
'@verdaccio/streams': 'link:../streams'
|
||||
async: 3.2.0
|
||||
debug: 4.1.1
|
||||
level: 5.0.1
|
||||
lodash: 4.17.20
|
||||
lowdb: 1.0.0
|
||||
mkdirp: 0.5.5
|
||||
devDependencies:
|
||||
'@types/minimatch': 3.0.3
|
||||
@ -375,8 +379,8 @@ importers:
|
||||
'@verdaccio/types': 'workspace:10.0.0-alpha.1'
|
||||
async: ^3.2.0
|
||||
debug: ^4.1.1
|
||||
level: 5.0.1
|
||||
lodash: ^4.17.20
|
||||
lowdb: 1.0.0
|
||||
minimatch: ^3.0.4
|
||||
mkdirp: ^0.5.5
|
||||
rmdir-sync: ^1.0.1
|
||||
@ -6596,6 +6600,12 @@ packages:
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
|
||||
/@types/lowdb/1.0.9:
|
||||
dependencies:
|
||||
'@types/lodash': 4.14.165
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha512-LBRG5EPXFOJDoJc9jACstMhtMP+u+UkPYllBeGQXXKiaHc+uzJs9+/Aynb/5KkX33DtrIiKyzNVTPQc/4RcD6A==
|
||||
/@types/mdast/3.0.3:
|
||||
dependencies:
|
||||
'@types/unist': 2.0.3
|
||||
@ -7531,6 +7541,7 @@ packages:
|
||||
dependencies:
|
||||
level-concat-iterator: 2.0.1
|
||||
xtend: 4.0.2
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -7542,6 +7553,7 @@ packages:
|
||||
level-concat-iterator: 2.0.1
|
||||
level-supports: 1.0.1
|
||||
xtend: 4.0.2
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -7553,6 +7565,7 @@ packages:
|
||||
level-concat-iterator: 2.0.1
|
||||
level-supports: 1.0.1
|
||||
xtend: 4.0.2
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -11097,6 +11110,7 @@ packages:
|
||||
dependencies:
|
||||
abstract-leveldown: 6.2.3
|
||||
inherits: 2.0.4
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -11719,6 +11733,7 @@ packages:
|
||||
inherits: 2.0.4
|
||||
level-codec: 9.0.2
|
||||
level-errors: 2.0.1
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -15721,9 +15736,11 @@ packages:
|
||||
resolution:
|
||||
integrity: sha512-33AmZ+xjZhg2JMCe+vDf6a9mzWukE7l+wAtesjE7KyteqqKjzxv7aVQeWnul1Ve26mWvEQqyPwl0OctNBfSR9w==
|
||||
/immediate/3.2.3:
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha1-0UD6j2FGWb1lQSMwl92qwlzdmRw=
|
||||
/immediate/3.3.0:
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==
|
||||
/import-cwd/2.1.0:
|
||||
@ -16424,7 +16441,6 @@ packages:
|
||||
resolution:
|
||||
integrity: sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
|
||||
/is-promise/2.2.2:
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
|
||||
/is-regex/1.1.1:
|
||||
@ -17651,11 +17667,13 @@ packages:
|
||||
/level-codec/9.0.2:
|
||||
dependencies:
|
||||
buffer: 5.6.0
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
integrity: sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ==
|
||||
/level-concat-iterator/2.0.1:
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -17663,6 +17681,7 @@ packages:
|
||||
/level-errors/2.0.1:
|
||||
dependencies:
|
||||
errno: 0.1.7
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -17672,6 +17691,7 @@ packages:
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.0
|
||||
xtend: 4.0.2
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -17683,12 +17703,14 @@ packages:
|
||||
inherits: 2.0.4
|
||||
ltgt: 2.2.1
|
||||
typedarray-to-buffer: 3.1.5
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha512-PeGjZsyMG4O89KHiez1zoMJxStnkM+oBIqgACjoo5PJqFiSUUm3GNod/KcbqN5ktyZa8jkG7I1T0P2u6HN9lIg==
|
||||
/level-packager/5.1.1:
|
||||
dependencies:
|
||||
encoding-down: 6.3.0
|
||||
levelup: 4.4.0
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -17696,6 +17718,7 @@ packages:
|
||||
/level-supports/1.0.1:
|
||||
dependencies:
|
||||
xtend: 4.0.2
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -17706,6 +17729,7 @@ packages:
|
||||
level-packager: 5.1.1
|
||||
leveldown: 5.6.0
|
||||
opencollective-postinstall: 2.0.3
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=8.6.0'
|
||||
requiresBuild: true
|
||||
@ -17716,6 +17740,7 @@ packages:
|
||||
abstract-leveldown: 6.2.3
|
||||
napi-macros: 2.0.0
|
||||
node-gyp-build: 4.1.1
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=8.6.0'
|
||||
requiresBuild: true
|
||||
@ -17728,6 +17753,7 @@ packages:
|
||||
level-iterator-stream: 4.0.2
|
||||
level-supports: 1.0.1
|
||||
xtend: 4.0.2
|
||||
dev: true
|
||||
engines:
|
||||
node: '>=6'
|
||||
resolution:
|
||||
@ -18290,6 +18316,18 @@ packages:
|
||||
node: '>=8'
|
||||
resolution:
|
||||
integrity: sha512-S0FayMXku80toa5sZ6Ro4C+s+EtFDCsyJNG/AzFMfX3AxD5Si4dZsgzm/kKnbOxHl5Cv8jBlno8+3XYIh2pNjQ==
|
||||
/lowdb/1.0.0:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.4
|
||||
is-promise: 2.2.2
|
||||
lodash: 4.17.20
|
||||
pify: 3.0.0
|
||||
steno: 0.4.4
|
||||
dev: false
|
||||
engines:
|
||||
node: '>=4'
|
||||
resolution:
|
||||
integrity: sha512-2+x8esE/Wb9SQ1F9IHaYWfsC9FIecLOPrK4g17FGEayjUWH172H6nwicRovGvSE2CPZouc2MCIqCI7h9d+GftQ==
|
||||
/lower-case/2.0.1:
|
||||
dependencies:
|
||||
tslib: 1.13.0
|
||||
@ -18356,6 +18394,7 @@ packages:
|
||||
resolution:
|
||||
integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||
/ltgt/2.2.1:
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=
|
||||
/lunr-mutable-indexes/2.3.2:
|
||||
@ -19146,6 +19185,7 @@ packages:
|
||||
resolution:
|
||||
integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
|
||||
/napi-macros/2.0.0:
|
||||
dev: true
|
||||
resolution:
|
||||
integrity: sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==
|
||||
/native-url/0.2.6:
|
||||
@ -19280,6 +19320,7 @@ packages:
|
||||
resolution:
|
||||
integrity: sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==
|
||||
/node-gyp-build/4.1.1:
|
||||
dev: true
|
||||
hasBin: true
|
||||
resolution:
|
||||
integrity: sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ==
|
||||
@ -19829,6 +19870,7 @@ packages:
|
||||
resolution:
|
||||
integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==
|
||||
/opencollective-postinstall/2.0.3:
|
||||
dev: true
|
||||
hasBin: true
|
||||
resolution:
|
||||
integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==
|
||||
@ -23917,6 +23959,12 @@ packages:
|
||||
node: '>=0.10.0'
|
||||
resolution:
|
||||
integrity: sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
|
||||
/steno/0.4.4:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.4
|
||||
dev: false
|
||||
resolution:
|
||||
integrity: sha1-BxEFvfwobmYVwEA8J+nXtdy4Vcs=
|
||||
/stream-browserify/2.0.2:
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
|
Loading…
Reference in New Issue
Block a user