2017-04-23 20:02:26 +02:00
'use strict' ;
let Cookies = require ( 'cookies' ) ;
let express = require ( 'express' ) ;
let bodyParser = require ( 'body-parser' ) ;
let Error = require ( 'http-errors' ) ;
let Path = require ( 'path' ) ;
let Middleware = require ( './middleware' ) ;
let Notify = require ( './notify' ) ;
let Utils = require ( './utils' ) ;
let expect _json = Middleware . expect _json ;
let match = Middleware . match ;
let media = Middleware . media ;
let validate _name = Middleware . validate _name ;
let validate _pkg = Middleware . validate _package ;
2014-11-13 18:13:37 +01:00
2015-04-08 22:54:59 +02:00
module . exports = function ( config , auth , storage ) {
2017-04-23 20:02:26 +02:00
let app = express . Router ( ) ;
let can = Middleware . allow ( auth ) ;
let notify = Notify . notify ;
2014-11-13 18:13:37 +01:00
// validate all of these params as a package name
// this might be too harsh, so ask if it causes trouble
2017-04-23 20:02:26 +02:00
app . param ( 'package' , validate _pkg ) ;
app . param ( 'filename' , validate _name ) ;
app . param ( 'tag' , validate _name ) ;
app . param ( 'version' , validate _name ) ;
app . param ( 'revision' , validate _name ) ;
app . param ( 'token' , validate _name ) ;
2014-11-13 18:13:37 +01:00
// these can't be safely put into express url for some reason
2017-04-23 20:02:26 +02:00
app . param ( '_rev' , match ( /^-rev$/ ) ) ;
app . param ( 'org_couchdb_user' , match ( /^org\.couchdb\.user:/ ) ) ;
app . param ( 'anything' , match ( /.*/ ) ) ;
2014-11-13 18:13:37 +01:00
2017-04-23 20:02:26 +02:00
app . use ( auth . basic _middleware ( ) ) ;
// app.use(auth.bearer_middleware())
app . use ( bodyParser . json ( { strict : false , limit : config . max _body _size || '10mb' } ) ) ;
app . use ( Middleware . anti _loop ( config ) ) ;
2014-11-13 18:13:37 +01:00
2015-06-29 03:10:54 +02:00
// encode / in a scoped package name to be matched as a single parameter in routes
app . use ( function ( req , res , next ) {
if ( req . url . indexOf ( '@' ) != - 1 ) {
// e.g.: /@org/pkg/1.2.3 -> /@org%2Fpkg/1.2.3, /@org%2Fpkg/1.2.3 -> /@org%2Fpkg/1.2.3
2017-04-23 20:02:26 +02:00
req . url = req . url . replace ( /^(\/@[^\/%]+)\/(?!$)/ , '$1%2F' ) ;
2015-06-29 03:10:54 +02:00
}
2017-04-23 20:02:26 +02:00
next ( ) ;
} ) ;
2015-06-29 03:10:54 +02:00
2014-11-16 13:37:50 +01:00
// for "npm whoami"
app . get ( '/whoami' , function ( req , res , next ) {
if ( req . headers . referer === 'whoami' ) {
2017-04-23 20:02:26 +02:00
next ( { username : req . remote _user . name } ) ;
2014-11-16 13:37:50 +01:00
} else {
2017-04-23 20:02:26 +02:00
next ( 'route' ) ;
2014-11-16 13:37:50 +01:00
}
2017-04-23 20:02:26 +02:00
} ) ;
2014-12-05 02:53:37 +01:00
app . get ( '/-/whoami' , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
next ( { username : req . remote _user . name } ) ;
} ) ;
2014-11-16 13:37:50 +01:00
2014-11-13 18:13:37 +01:00
// TODO: anonymous user?
app . get ( '/:package/:version?' , can ( 'access' ) , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
storage . get _package ( req . params . package , { req : req } , function ( err , info ) {
if ( err ) return next ( err ) ;
info = Utils . filter _tarball _urls ( info , req , config ) ;
2014-11-13 18:13:37 +01:00
2017-04-23 20:02:26 +02:00
let version = req . params . version ;
if ( ! version ) return next ( info ) ;
2014-11-13 18:13:37 +01:00
2017-04-23 20:02:26 +02:00
let t = Utils . get _version ( info , version ) ;
if ( t != null ) return next ( t ) ;
2014-11-13 18:13:37 +01:00
if ( info [ 'dist-tags' ] != null ) {
if ( info [ 'dist-tags' ] [ version ] != null ) {
2017-04-23 20:02:26 +02:00
version = info [ 'dist-tags' ] [ version ] ;
t = Utils . get _version ( info , version ) ;
if ( t != null ) return next ( t ) ;
2014-11-13 18:13:37 +01:00
}
}
2017-04-23 20:02:26 +02:00
return next ( Error [ 404 ] ( 'version not found: ' + req . params . version ) ) ;
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
app . get ( '/:package/-/:filename' , can ( 'access' ) , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
let stream = storage . get _tarball ( req . params . package , req . params . filename ) ;
2014-11-13 18:13:37 +01:00
stream . on ( 'content-length' , function ( v ) {
2017-04-23 20:02:26 +02:00
res . header ( 'Content-Length' , v ) ;
} ) ;
2014-11-13 18:13:37 +01:00
stream . on ( 'error' , function ( err ) {
2017-04-23 20:02:26 +02:00
return res . report _error ( err ) ;
} ) ;
res . header ( 'Content-Type' , 'application/octet-stream' ) ;
stream . pipe ( res ) ;
} ) ;
2014-11-13 18:13:37 +01:00
// searching packages
2017-04-21 20:33:55 +02:00
app . get ( '/-/all(\/since)?' , function ( req , res , next ) {
2017-04-23 22:28:35 +02:00
let received _end = false ;
let response _finished = false ;
let processing _pkgs = 0 ;
let firstPackage = true ;
2015-05-17 00:29:16 +02:00
2017-04-23 22:28:35 +02:00
res . status ( 200 ) ;
2017-04-21 20:33:55 +02:00
/ *
* Offical NPM registry ( registry . npmjs . org ) no longer return whole database ,
* They only return packages matched with keyword in ` referer: search pkg-name ` ,
* And NPM client will request server in every search .
*
* The magic number 99999 was sent by NPM registry . Modify it may caused strange
* behaviour in the future .
*
* BTW : NPM will not return result if user - agent does not contain string 'npm' ,
* See : method 'request' in up - storage . js
*
* If there is no cache in local , NPM will request / - / a l l , t h e n g e t r e s p o n s e w i t h
2017-04-22 10:28:47 +02:00
* _updated : 99999 , 'Date' in response header was Mon , 10 Oct 1983 00 : 12 : 48 GMT ,
* this will make NPM always query from server
2017-04-21 20:33:55 +02:00
*
* Data structure also different , whel request / - / a l l , r e s p o n s e i s a n o b j e c t , b u t
* when request / - / a l l / s i n c e , r e s p o n s e i s a n a r r a y
* /
2017-04-23 22:28:35 +02:00
const respShouldBeArray = req . path . endsWith ( '/since' ) ;
res . set ( 'Date' , 'Mon, 10 Oct 1983 00:12:48 GMT' ) ;
2017-04-22 10:28:47 +02:00
2017-04-21 20:33:55 +02:00
if ( respShouldBeArray ) {
2017-04-23 22:28:35 +02:00
res . write ( '[' ) ;
2017-04-21 20:33:55 +02:00
} else {
res . write ( '{"_updated":' + 99999 ) ;
}
2017-04-23 20:02:26 +02:00
let stream = storage . search ( req . query . startkey || 0 , { req : req } ) ;
2015-05-17 00:29:16 +02:00
stream . on ( 'data' , function each ( pkg ) {
2017-04-23 20:02:26 +02:00
processing _pkgs ++ ;
2015-05-17 00:29:16 +02:00
auth . allow _access ( pkg . name , req . remote _user , function ( err , allowed ) {
2017-04-23 20:02:26 +02:00
processing _pkgs -- ;
2015-05-17 00:29:16 +02:00
if ( err ) {
if ( err . status && String ( err . status ) . match ( /^4\d\d$/ ) ) {
// auth plugin returns 4xx user error,
// that's equivalent of !allowed basically
2017-04-23 20:02:26 +02:00
allowed = false ;
2015-05-17 00:29:16 +02:00
} else {
2017-04-23 20:02:26 +02:00
stream . abort ( err ) ;
2015-04-08 22:54:59 +02:00
}
2015-05-17 00:29:16 +02:00
}
if ( allowed ) {
2017-04-21 20:33:55 +02:00
if ( respShouldBeArray ) {
2017-04-23 22:28:35 +02:00
res . write ( ` ${ firstPackage ? '' : ',' } ${ JSON . stringify ( pkg ) } \n ` ) ;
2017-04-21 20:33:55 +02:00
if ( firstPackage ) {
2017-04-23 22:28:35 +02:00
firstPackage = false ;
2017-04-21 20:33:55 +02:00
}
} else {
2017-04-23 22:28:35 +02:00
res . write ( ',\n' + JSON . stringify ( pkg . name ) + ':' + JSON . stringify ( pkg ) ) ;
2017-04-21 20:33:55 +02:00
}
2015-05-17 00:29:16 +02:00
}
2015-04-08 22:54:59 +02:00
2017-04-23 20:02:26 +02:00
check _finish ( ) ;
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
2017-04-23 20:02:26 +02:00
stream . on ( 'error' , function ( _err ) {
res . socket . destroy ( ) ;
} ) ;
2015-05-17 00:29:16 +02:00
2017-04-23 20:02:26 +02:00
stream . on ( 'end' , function ( ) {
received _end = true ;
check _finish ( ) ;
} ) ;
2015-05-17 00:29:16 +02:00
function check _finish ( ) {
2017-04-23 20:02:26 +02:00
if ( ! received _end ) return ;
if ( processing _pkgs ) return ;
if ( response _finished ) return ;
2015-05-17 00:29:16 +02:00
2017-04-23 22:28:35 +02:00
response _finished = true ;
2017-04-21 20:33:55 +02:00
if ( respShouldBeArray ) {
2017-04-23 22:28:35 +02:00
res . end ( ']\n' ) ;
2017-04-21 20:33:55 +02:00
} else {
2017-04-23 22:28:35 +02:00
res . end ( '}\n' ) ;
2017-04-21 20:33:55 +02:00
}
2015-05-17 00:29:16 +02:00
}
2017-04-23 20:02:26 +02:00
} ) ;
2014-11-13 18:13:37 +01:00
// placeholder 'cause npm require to be authenticated to publish
// we do not do any real authentication yet
2015-02-06 19:59:18 +01:00
app . post ( '/_session' , Cookies . express ( ) , function ( req , res , next ) {
2014-11-13 18:13:37 +01:00
res . cookies . set ( 'AuthSession' , String ( Math . random ( ) ) , {
// npmjs.org sets 10h expire
2017-04-23 20:02:26 +02:00
expires : new Date ( Date . now ( ) + 10 * 60 * 60 * 1000 ) ,
} ) ;
next ( { ok : true , name : 'somebody' , roles : [ ] } ) ;
} ) ;
2014-11-13 18:13:37 +01:00
app . get ( '/-/user/:org_couchdb_user' , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
res . status ( 200 ) ;
2014-11-13 19:32:31 +01:00
next ( {
2014-11-13 18:13:37 +01:00
ok : 'you are authenticated as "' + req . remote _user . name + '"' ,
2017-04-23 20:02:26 +02:00
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
app . put ( '/-/user/:org_couchdb_user/:_rev?/:revision?' , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
let token = ( req . body . name && req . body . password )
2014-11-24 20:46:37 +01:00
? auth . aes _encrypt ( req . body . name + ':' + req . body . password ) . toString ( 'base64' )
2017-04-23 20:02:26 +02:00
: undefined ;
2014-11-13 18:13:37 +01:00
if ( req . remote _user . name != null ) {
2017-04-23 20:02:26 +02:00
res . status ( 201 ) ;
2014-11-13 19:32:31 +01:00
return next ( {
2017-04-23 20:02:26 +02:00
ok : 'you are authenticated as \'' + req . remote _user . name + '\'' ,
// token: auth.issue_token(req.remote_user),
2014-11-24 20:46:37 +01:00
token : token ,
2017-04-23 20:02:26 +02:00
} ) ;
2014-11-13 18:13:37 +01:00
} else {
if ( typeof ( req . body . name ) !== 'string' || typeof ( req . body . password ) !== 'string' ) {
if ( typeof ( req . body . password _sha ) ) {
2017-04-23 20:02:26 +02:00
return next ( Error [ 422 ] ( 'your npm version is outdated\nPlease update to npm@1.4.5 or greater.\nSee https://github.com/rlidwka/sinopia/issues/93 for details.' ) ) ;
2014-11-13 18:13:37 +01:00
} else {
2017-04-23 20:02:26 +02:00
return next ( Error [ 422 ] ( 'user/password is not found in request (npm issue?)' ) ) ;
2014-11-13 18:13:37 +01:00
}
}
2014-11-16 13:37:50 +01:00
auth . add _user ( req . body . name , req . body . password , function ( err , user ) {
2014-11-13 18:13:37 +01:00
if ( err ) {
2015-02-12 12:18:47 +01:00
if ( err . status >= 400 && err . status < 500 ) {
// With npm registering is the same as logging in,
// and npm accepts only an 409 error.
// So, changing status code here.
2017-04-23 20:02:26 +02:00
return next ( Error [ 409 ] ( err . message ) ) ;
2014-11-13 18:13:37 +01:00
}
2017-04-23 20:02:26 +02:00
return next ( err ) ;
2014-11-13 18:13:37 +01:00
}
2017-04-23 20:02:26 +02:00
req . remote _user = user ;
res . status ( 201 ) ;
2014-11-16 13:37:50 +01:00
return next ( {
2017-04-23 20:02:26 +02:00
ok : 'user \'' + req . body . name + '\' created' ,
// token: auth.issue_token(req.remote_user),
2014-11-24 20:46:37 +01:00
token : token ,
2017-04-23 20:02:26 +02:00
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
}
2017-04-23 20:02:26 +02:00
} ) ;
2014-11-13 18:13:37 +01:00
2016-10-12 01:53:20 +02:00
app . delete ( '/-/user/token/*' , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
res . status ( 200 ) ;
2016-08-10 12:14:08 +02:00
next ( {
ok : 'Logged out' ,
2017-04-23 20:02:26 +02:00
} ) ;
} ) ;
2016-08-10 12:14:08 +02:00
2015-05-10 17:23:31 +02:00
function tag _package _version ( req , res , next ) {
2017-04-23 20:02:26 +02:00
if ( typeof ( req . body ) !== 'string' ) return next ( 'route' ) ;
2014-11-13 18:13:37 +01:00
2017-04-23 20:02:26 +02:00
let tags = { } ;
tags [ req . params . tag ] = req . body ;
2015-05-10 17:23:31 +02:00
storage . merge _tags ( req . params . package , tags , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : 'package tagged' } ) ;
} ) ;
2015-05-10 17:23:31 +02:00
}
// tagging a package
app . put ( '/:package/:tag' ,
2017-04-23 20:02:26 +02:00
can ( 'publish' ) , media ( 'application/json' ) , tag _package _version ) ;
2015-05-10 17:23:31 +02:00
app . post ( '/-/package/:package/dist-tags/:tag' ,
2017-04-23 20:02:26 +02:00
can ( 'publish' ) , media ( 'application/json' ) , tag _package _version ) ;
2015-05-10 17:23:31 +02:00
app . put ( '/-/package/:package/dist-tags/:tag' ,
2017-04-23 20:02:26 +02:00
can ( 'publish' ) , media ( 'application/json' ) , tag _package _version ) ;
2015-05-10 17:23:31 +02:00
2017-04-23 20:02:26 +02:00
app . delete ( '/-/package/:package/dist-tags/:tag' , can ( 'publish' ) , function ( req , res , next ) {
let tags = { } ;
tags [ req . params . tag ] = null ;
2015-05-10 17:23:31 +02:00
storage . merge _tags ( req . params . package , tags , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : 'tag removed' } ) ;
} ) ;
} ) ;
2015-05-10 17:23:31 +02:00
app . get ( '/-/package/:package/dist-tags' , can ( 'access' ) , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
storage . get _package ( req . params . package , { req : req } , function ( err , info ) {
if ( err ) return next ( err ) ;
2015-05-10 17:23:31 +02:00
2017-04-23 20:02:26 +02:00
next ( info [ 'dist-tags' ] ) ;
} ) ;
} ) ;
2015-05-10 17:23:31 +02:00
app . post ( '/-/package/:package/dist-tags' ,
can ( 'publish' ) , media ( 'application/json' ) , expect _json ,
function ( req , res , next ) {
storage . merge _tags ( req . params . package , req . body , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : 'tags updated' } ) ;
} ) ;
} ) ;
2015-05-10 17:23:31 +02:00
app . put ( '/-/package/:package/dist-tags' ,
can ( 'publish' ) , media ( 'application/json' ) , expect _json ,
function ( req , res , next ) {
storage . replace _tags ( req . params . package , req . body , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : 'tags updated' } ) ;
} ) ;
} ) ;
2015-05-10 17:23:31 +02:00
app . delete ( '/-/package/:package/dist-tags' ,
can ( 'publish' ) , media ( 'application/json' ) ,
function ( req , res , next ) {
storage . replace _tags ( req . params . package , { } , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : 'tags removed' } ) ;
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
// publishing a package
app . put ( '/:package/:_rev?/:revision?' , can ( 'publish' ) , media ( 'application/json' ) , expect _json , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
let name = req . params . package ;
2014-11-13 18:13:37 +01:00
if ( Object . keys ( req . body ) . length == 1 && Utils . is _object ( req . body . users ) ) {
// 501 status is more meaningful, but npm doesn't show error message for 5xx
2017-04-23 20:02:26 +02:00
return next ( Error [ 404 ] ( 'npm star|unstar calls are not implemented' ) ) ;
2014-11-13 18:13:37 +01:00
}
try {
2017-04-23 20:02:26 +02:00
var metadata = Utils . validate _metadata ( req . body , name ) ;
2014-11-13 18:13:37 +01:00
} catch ( err ) {
2017-04-23 20:02:26 +02:00
return next ( Error [ 422 ] ( 'bad incoming package data' ) ) ;
2014-11-13 18:13:37 +01:00
}
if ( req . params . _rev ) {
storage . change _package ( name , metadata , req . params . revision , function ( err ) {
2017-04-23 20:02:26 +02:00
after _change ( err , 'package changed' ) ;
} ) ;
2014-11-13 18:13:37 +01:00
} else {
storage . add _package ( name , metadata , function ( err ) {
2017-04-23 20:02:26 +02:00
after _change ( err , 'created new package' ) ;
} ) ;
2014-11-13 18:13:37 +01:00
}
function after _change ( err , ok _message ) {
// old npm behaviour
if ( metadata . _attachments == null ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : ok _message } ) ;
2014-11-13 18:13:37 +01:00
}
// npm-registry-client 0.3+ embeds tarball into the json upload
// https://github.com/isaacs/npm-registry-client/commit/e9fbeb8b67f249394f735c74ef11fe4720d46ca0
// issue #31, dealing with it here:
if ( typeof ( metadata . _attachments ) !== 'object'
2017-04-23 20:02:26 +02:00
|| Object . keys ( metadata . _attachments ) . length !== 1
|| typeof ( metadata . versions ) !== 'object'
|| Object . keys ( metadata . versions ) . length !== 1 ) {
2014-11-13 18:13:37 +01:00
// npm is doing something strange again
// if this happens in normal circumstances, report it as a bug
2017-04-23 20:02:26 +02:00
return next ( Error [ 400 ] ( 'unsupported registry call' ) ) ;
2014-11-13 18:13:37 +01:00
}
2017-04-23 20:02:26 +02:00
if ( err && err . status != 409 ) return next ( err ) ;
2014-11-13 18:13:37 +01:00
// at this point document is either created or existed before
2017-04-23 20:02:26 +02:00
let t1 = Object . keys ( metadata . _attachments ) [ 0 ] ;
2014-11-16 18:44:46 +01:00
create _tarball ( Path . basename ( t1 ) , metadata . _attachments [ t1 ] , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
2014-11-13 18:13:37 +01:00
2017-04-23 20:02:26 +02:00
let t2 = Object . keys ( metadata . versions ) [ 0 ] ;
metadata . versions [ t2 ] . readme = metadata . readme != null ? String ( metadata . readme ) : '' ;
2014-11-13 18:13:37 +01:00
create _version ( t2 , metadata . versions [ t2 ] , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
2014-11-13 18:13:37 +01:00
add _tags ( metadata [ 'dist-tags' ] , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
notify ( metadata , config ) ;
res . status ( 201 ) ;
return next ( { ok : ok _message } ) ;
} ) ;
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
}
function create _tarball ( filename , data , cb ) {
2017-04-23 20:02:26 +02:00
let stream = storage . add _tarball ( name , filename ) ;
2014-11-13 18:13:37 +01:00
stream . on ( 'error' , function ( err ) {
2017-04-23 20:02:26 +02:00
cb ( err ) ;
} ) ;
2014-11-13 18:13:37 +01:00
stream . on ( 'success' , function ( ) {
2017-04-23 20:02:26 +02:00
cb ( ) ;
} ) ;
2014-11-13 18:13:37 +01:00
// this is dumb and memory-consuming, but what choices do we have?
2017-04-23 20:02:26 +02:00
stream . end ( new Buffer ( data . data , 'base64' ) ) ;
stream . done ( ) ;
2014-11-13 18:13:37 +01:00
}
function create _version ( version , data , cb ) {
2017-04-23 20:02:26 +02:00
storage . add _version ( name , version , data , null , cb ) ;
2014-11-13 18:13:37 +01:00
}
function add _tags ( tags , cb ) {
2017-04-23 20:02:26 +02:00
storage . merge _tags ( name , tags , cb ) ;
2014-11-13 18:13:37 +01:00
}
2017-04-23 20:02:26 +02:00
} ) ;
2014-11-13 18:13:37 +01:00
// unpublishing an entire package
app . delete ( '/:package/-rev/*' , can ( 'publish' ) , function ( req , res , next ) {
storage . remove _package ( req . params . package , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : 'package removed' } ) ;
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
// removing a tarball
app . delete ( '/:package/-/:filename/-rev/:revision' , can ( 'publish' ) , function ( req , res , next ) {
storage . remove _tarball ( req . params . package , req . params . filename , req . params . revision , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : 'tarball removed' } ) ;
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
// uploading package tarball
app . put ( '/:package/-/:filename/*' , can ( 'publish' ) , media ( 'application/octet-stream' ) , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
let name = req . params . package ;
2014-11-13 18:13:37 +01:00
2017-04-23 20:02:26 +02:00
let stream = storage . add _tarball ( name , req . params . filename ) ;
req . pipe ( stream ) ;
2014-11-13 18:13:37 +01:00
// checking if end event came before closing
2017-04-23 20:02:26 +02:00
let complete = false ;
2014-11-13 18:13:37 +01:00
req . on ( 'end' , function ( ) {
2017-04-23 20:02:26 +02:00
complete = true ;
stream . done ( ) ;
} ) ;
2014-11-13 18:13:37 +01:00
req . on ( 'close' , function ( ) {
if ( ! complete ) {
2017-04-23 20:02:26 +02:00
stream . abort ( ) ;
2014-11-13 18:13:37 +01:00
}
2017-04-23 20:02:26 +02:00
} ) ;
2014-11-13 18:13:37 +01:00
stream . on ( 'error' , function ( err ) {
2017-04-23 20:02:26 +02:00
return res . report _error ( err ) ;
} ) ;
2014-11-13 18:13:37 +01:00
stream . on ( 'success' , function ( ) {
2017-04-23 20:02:26 +02:00
res . status ( 201 ) ;
2014-11-13 19:32:31 +01:00
return next ( {
2017-04-23 20:02:26 +02:00
ok : 'tarball uploaded successfully' ,
} ) ;
} ) ;
} ) ;
2014-11-13 18:13:37 +01:00
// adding a version
app . put ( '/:package/:version/-tag/:tag' , can ( 'publish' ) , media ( 'application/json' ) , expect _json , function ( req , res , next ) {
2017-04-23 20:02:26 +02:00
let name = req . params . package ;
let version = req . params . version ;
let tag = req . params . tag ;
2014-11-13 18:13:37 +01:00
storage . add _version ( name , version , req . body , tag , function ( err ) {
2017-04-23 20:02:26 +02:00
if ( err ) return next ( err ) ;
res . status ( 201 ) ;
return next ( { ok : 'package published' } ) ;
} ) ;
} ) ;
return app ;
} ;
2014-11-13 18:13:37 +01:00