@@ -4,15 +4,39 @@ import Path from 'path';
44// $FlowFixMe
55import async from 'async' ;
66import mkdirp from 'mkdirp' ;
7+ import stream from 'stream' ;
78
89import LocalDriver , { noSuchFile } from './local-fs' ;
910import { loadPrivatePackages } from './pkg-utils' ;
1011
11- import { IPackageStorage , IPluginStorage , StorageList , LocalStorage , Logger , Config , Callback } from '@verdaccio/types' ;
12- import { getInternalError } from "@verdaccio/commons-api/lib" ;
12+ import {
13+ Callback ,
14+ Config ,
15+ IPackageStorage ,
16+ IPluginStorage ,
17+ LocalStorage ,
18+ Logger ,
19+ StorageList ,
20+ Token ,
21+ TokenFilter
22+ } from '@verdaccio/types' ;
23+
24+ import level from 'level' ;
25+ import { getInternalError } from '@verdaccio/commons-api/lib' ;
1326
1427const DEPRECATED_DB_NAME = '.sinopia-db.json' ;
1528const DB_NAME = '.verdaccio-db.json' ;
29+ const TOKEN_DB_NAME = '.token-db' ;
30+
31+ interface Level {
32+ put ( key : string , token , fn ?: Function ) : void ;
33+
34+ get ( key : string , fn ?: Function ) : void ;
35+
36+ del ( key : string , fn ?: Function ) : void ;
37+
38+ createReadStream ( options ?: object ) : stream . Readable ;
39+ }
1640
1741/**
1842 * Handle local database.
@@ -23,6 +47,7 @@ class LocalDatabase implements IPluginStorage<{}> {
2347 public data : LocalStorage ;
2448 public config : Config ;
2549 public locked : boolean ;
50+ public tokenDb ;
2651
2752 /**
2853 * Load an parse the local json database.
@@ -40,11 +65,11 @@ class LocalDatabase implements IPluginStorage<{}> {
4065 this . _sync ( ) ;
4166 }
4267
43- getSecret ( ) : Promise < string > {
68+ public getSecret ( ) : Promise < string > {
4469 return Promise . resolve ( this . data . secret ) ;
4570 }
4671
47- setSecret ( secret : string ) : Promise < string > {
72+ public setSecret ( secret : string ) : Promise < Error | null > {
4873 return new Promise ( resolve => {
4974 this . data . secret = secret ;
5075
@@ -57,7 +82,7 @@ class LocalDatabase implements IPluginStorage<{}> {
5782 * @param {* } name
5883 * @return {Error|* }
5984 */
60- public add ( name : string , cb : Callback ) {
85+ public add ( name : string , cb : Callback ) : void {
6186 if ( this . data . list . indexOf ( name ) === - 1 ) {
6287 this . data . list . push ( name ) ;
6388
@@ -68,7 +93,7 @@ class LocalDatabase implements IPluginStorage<{}> {
6893 }
6994 }
7095
71- public search ( onPackage : Callback , onEnd : Callback , validateName : any ) : void {
96+ public search ( onPackage : Callback , onEnd : Callback , validateName : ( name : string ) => boolean ) : void {
7297 const storages = this . _getCustomPackageLocalStorages ( ) ;
7398 this . logger . trace ( `local-storage: [search]: ${ JSON . stringify ( storages ) } ` ) ;
7499 const base = Path . dirname ( this . config . self_path ) ;
@@ -158,40 +183,12 @@ class LocalDatabase implements IPluginStorage<{}> {
158183 ) ;
159184 }
160185
161- private _getTime ( time : number , mtime : Date ) {
162- return time ? time : mtime ;
163- }
164-
165- private _getCustomPackageLocalStorages ( ) {
166- const storages = { } ;
167-
168- // add custom storage if exist
169- if ( this . config . storage ) {
170- storages [ this . config . storage ] = true ;
171- }
172-
173- const { packages } = this . config ;
174-
175- if ( packages ) {
176- const listPackagesConf = Object . keys ( packages || { } ) ;
177-
178- listPackagesConf . map ( pkg => {
179- const storage = packages [ pkg ] . storage ;
180- if ( storage ) {
181- storages [ storage ] = false ;
182- }
183- } ) ;
184- }
185-
186- return storages ;
187- }
188-
189186 /**
190187 * Remove an element from the database.
191188 * @param {* } name
192189 * @return {Error|* }
193190 */
194- public remove ( name : string , cb : Callback ) {
191+ public remove ( name : string , cb : Callback ) : void {
195192 this . get ( ( err , data ) => {
196193 if ( err ) {
197194 cb ( getInternalError ( 'error remove private package' ) ) ;
@@ -213,20 +210,119 @@ class LocalDatabase implements IPluginStorage<{}> {
213210 * Return all database elements.
214211 * @return {Array }
215212 */
216- public get ( cb : Callback ) {
213+ public get ( cb : Callback ) : void {
217214 const list = this . data . list ;
218215 const totalItems = this . data . list . length ;
219216
220217 cb ( null , list ) ;
221218
222- this . logger . trace ( { totalItems} , 'local-storage: [get] full list of packages (@{totalItems}) has been fetched' ) ;
219+ this . logger . trace ( { totalItems } , 'local-storage: [get] full list of packages (@{totalItems}) has been fetched' ) ;
220+ }
221+
222+ public getPackageStorage ( packageName : string ) : IPackageStorage {
223+ const packageAccess = this . config . getMatchedPackagesSpec ( packageName ) ;
224+
225+ const packagePath : string = this . _getLocalStoragePath ( packageAccess ? packageAccess . storage : undefined ) ;
226+ this . logger . trace ( { packagePath } , '[local-storage/getPackageStorage]: storage selected: @{packagePath}' ) ;
227+
228+ if ( _ . isString ( packagePath ) === false ) {
229+ this . logger . debug ( { name : packageName } , 'this package has no storage defined: @{name}' ) ;
230+ return ;
231+ }
232+
233+ const packageStoragePath : string = Path . join ( Path . resolve ( Path . dirname ( this . config . self_path || '' ) , packagePath ) , packageName ) ;
234+
235+ this . logger . trace ( { packageStoragePath } , '[local-storage/getPackageStorage]: storage path: @{packageStoragePath}' ) ;
236+
237+ return new LocalDriver ( packageStoragePath , this . logger ) ;
238+ }
239+
240+ public clean ( ) : void {
241+ this . _sync ( ) ;
242+ }
243+
244+ public saveToken ( token : Token ) : Promise < void > {
245+ const key = this . _getTokenKey ( token ) ;
246+ const db = this . getTokenDb ( ) ;
247+
248+ return new Promise ( ( resolve , reject ) => {
249+ db . put ( key , token , err => {
250+ if ( err ) {
251+ reject ( err ) ;
252+ return ;
253+ }
254+ resolve ( ) ;
255+ } ) ;
256+ } ) ;
257+ }
258+
259+ public deleteToken ( user : string , tokenKey : string ) : Promise < void > {
260+ const key = this . _compoundTokenKey ( user , tokenKey ) ;
261+ const db = this . getTokenDb ( ) ;
262+ return new Promise ( ( resolve , reject ) => {
263+ db . del ( key , err => {
264+ if ( err ) {
265+ reject ( err ) ;
266+ return ;
267+ }
268+ resolve ( ) ;
269+ } ) ;
270+ } ) ;
271+ }
272+
273+ public readTokens ( filter : TokenFilter ) : Promise < Token [ ] > {
274+ return new Promise ( ( resolve , reject ) => {
275+ const tokens : Token [ ] = [ ] ;
276+ const key = filter . user + ':' ;
277+ const db = this . getTokenDb ( ) ;
278+ const stream = db . createReadStream ( {
279+ gte : key ,
280+ lte : String . fromCharCode ( key . charCodeAt ( 0 ) + 1 )
281+ } ) ;
282+
283+ stream . on ( 'data' , data => {
284+ tokens . push ( data . value ) ;
285+ } ) ;
286+
287+ stream . once ( 'end' , ( ) => resolve ( tokens ) ) ;
288+
289+ stream . once ( 'error' , err => reject ( err ) ) ;
290+ } ) ;
291+ }
292+
293+ private _getTime ( time : number , mtime : Date ) : number | Date {
294+ return time ? time : mtime ;
295+ }
296+
297+ private _getCustomPackageLocalStorages ( ) : object {
298+ const storages = { } ;
299+
300+ // add custom storage if exist
301+ if ( this . config . storage ) {
302+ storages [ this . config . storage ] = true ;
303+ }
304+
305+ const { packages } = this . config ;
306+
307+ if ( packages ) {
308+ const listPackagesConf = Object . keys ( packages || { } ) ;
309+
310+ listPackagesConf . map ( pkg => {
311+ const storage = packages [ pkg ] . storage ;
312+ if ( storage ) {
313+ storages [ storage ] = false ;
314+ }
315+ } ) ;
316+ }
317+
318+ return storages ;
223319 }
224320
225321 /**
226322 * Syncronize {create} database whether does not exist.
227323 * @return {Error|* }
228324 */
229- private _sync ( ) {
325+ private _sync ( ) : Error | null {
230326 this . logger . debug ( '[local-storage/_sync]: init sync database' ) ;
231327
232328 if ( this . locked ) {
@@ -258,24 +354,6 @@ class LocalDatabase implements IPluginStorage<{}> {
258354 }
259355 }
260356
261- public getPackageStorage ( packageName : string ) : IPackageStorage {
262- const packageAccess = this . config . getMatchedPackagesSpec ( packageName ) ;
263-
264- const packagePath : string = this . _getLocalStoragePath ( packageAccess ? packageAccess . storage : undefined ) ;
265- this . logger . trace ( { packagePath } , '[local-storage/getPackageStorage]: storage selected: @{packagePath}' ) ;
266-
267- if ( _ . isString ( packagePath ) === false ) {
268- this . logger . debug ( { name : packageName } , 'this package has no storage defined: @{name}' ) ;
269- return ;
270- }
271-
272- const packageStoragePath : string = Path . join ( Path . resolve ( Path . dirname ( this . config . self_path || '' ) , packagePath ) , packageName ) ;
273-
274- this . logger . trace ( { packageStoragePath } , '[local-storage/getPackageStorage]: storage path: @{packageStoragePath}' ) ;
275-
276- return new LocalDriver ( packageStoragePath , this . logger ) ;
277- }
278-
279357 /**
280358 * Verify the right local storage location.
281359 * @param {String } path
@@ -301,23 +379,22 @@ class LocalDatabase implements IPluginStorage<{}> {
301379 * @return {string|String|* }
302380 * @private
303381 */
304- private _buildStoragePath ( config : Config ) {
305- const dbGenPath = function ( dbName : string ) {
306- return Path . join ( Path . resolve ( Path . dirname ( config . self_path || '' ) , config . storage as string , dbName ) ) ;
307- } ;
308-
309- const sinopiadbPath : string = dbGenPath ( DEPRECATED_DB_NAME ) ;
382+ private _buildStoragePath ( config : Config ) : string {
383+ const sinopiadbPath : string = this . _dbGenPath ( DEPRECATED_DB_NAME , config ) ;
310384 try {
311385 fs . accessSync ( sinopiadbPath , fs . constants . F_OK ) ;
312386 return sinopiadbPath ;
313387 } catch ( err ) {
314- if ( err . code === noSuchFile ) {
315- return dbGenPath ( DB_NAME ) ;
388+ if ( err . code === noSuchFile ) {
389+ return this . _dbGenPath ( DB_NAME , config ) ;
316390 }
317391
318- throw err
392+ throw err ;
319393 }
394+ }
320395
396+ private _dbGenPath ( dbName : string , config : Config ) : string {
397+ return Path . join ( Path . resolve ( Path . dirname ( config . self_path || '' ) , config . storage as string , dbName ) ) ;
321398 }
322399
323400 /**
@@ -344,6 +421,25 @@ class LocalDatabase implements IPluginStorage<{}> {
344421 return emptyDatabase ;
345422 }
346423 }
424+
425+ private getTokenDb ( ) : Level {
426+ if ( ! this . tokenDb ) {
427+ this . tokenDb = level ( this . _dbGenPath ( TOKEN_DB_NAME , this . config ) , {
428+ valueEncoding : 'json'
429+ } ) ;
430+ }
431+
432+ return this . tokenDb ;
433+ }
434+
435+ private _getTokenKey ( token : Token ) : string {
436+ const { user, key } = token ;
437+ return this . _compoundTokenKey ( user , key ) ;
438+ }
439+
440+ private _compoundTokenKey ( user : string , key : string ) : string {
441+ return `${ user } :${ key } ` ;
442+ }
347443}
348444
349445export default LocalDatabase ;
0 commit comments