0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-30 22:34:10 -05:00

refactor: create cryto utils

This commit is contained in:
Juan Picado @jotadeveloper 2018-06-01 22:17:01 +02:00
parent 4a5116fb5d
commit 87e3faa624
No known key found for this signature in database
GPG key ID: 18AC54485952D158
10 changed files with 75 additions and 66 deletions

View file

@ -17,13 +17,13 @@ export default function(route: Router, auth: IAuth) {
route.put('/-/user/:org_couchdb_user/:_rev?/:revision?', function(req: $RequestExtend, res: $Response, next: $NextFunctionVer) {
let token = (req.body.name && req.body.password)
? auth.aes_encrypt(new Buffer(req.body.name + ':' + req.body.password)).toString('base64')
? auth.aesEncrypt(new Buffer(req.body.name + ':' + req.body.password)).toString('base64')
: undefined;
if (_.isNil(req.remote_user.name) === false) {
res.status(201);
return next({
ok: 'you are authenticated as \'' + req.remote_user.name + '\'',
token: token,
token,
});
} else {
auth.add_user(req.body.name, req.body.password, function(err, user) {

View file

@ -1,6 +1,5 @@
// @flow
import crypto from 'crypto';
import _ from 'lodash';
import {
validate_name as utilValidateName,
@ -8,6 +7,7 @@ import {
isObject,
ErrorCode} from '../lib/utils';
import {HEADERS} from '../lib/constants';
import {stringToMD5} from '../lib/crypto-utils';
import type {$ResponseExtend, $RequestExtend, $NextFunctionVer, IAuth} from '../../types';
import type {Config} from '@verdaccio/types';
@ -97,18 +97,6 @@ export function anti_loop(config: Config) {
};
}
/**
* Express doesn't do etags with requests <= 1024b
* we use md5 here, it works well on 1k+ bytes, but sucks with fewer data
* could improve performance using crc32 after benchmarks.
* @param {Object} data
* @return {String}
*/
function md5sum(data) {
return crypto.createHash('md5').update(data).digest('hex');
}
export function allow(auth: IAuth) {
return function(action: string) {
return function(req: $RequestExtend, res: $ResponseExtend, next: $NextFunctionVer) {
@ -155,7 +143,7 @@ export function allow(auth: IAuth) {
// don't send etags with errors
if (!res.statusCode || (res.statusCode >= 200 && res.statusCode < 300)) {
res.header('ETag', '"' + md5sum(body) + '"');
res.header('ETag', '"' + stringToMD5(body) + '"');
}
} else {
// send(null), send(204), etc.

View file

@ -1,13 +1,13 @@
// @flow
import {loadPlugin} from '../lib/plugin-loader';
import Crypto from 'crypto';
import jwt from 'jsonwebtoken';
import {ErrorCode} from './utils';
import type {Config, Logger, Callback} from '@verdaccio/types';
import type {$Response, NextFunction} from 'express';
import type {$RequestExtend} from '../../types';
import {aesDecrypt, aesEncrypt} from './crypto-utils';
const LoggerApi = require('./logger');
/**
@ -254,7 +254,9 @@ class Auth {
this.logger.warn('basic authentication is deprecated, please use JWT instead');
return credentials;
} else if (scheme.toUpperCase() === 'BEARER') {
credentials = this.aes_decrypt(new Buffer(parts[1], 'base64')).toString('utf8');
const token = new Buffer(parts[1], 'base64');
credentials = aesDecrypt(token, this.secret).toString('utf8');
return credentials;
} else {
return;
@ -331,25 +333,8 @@ class Auth {
/**
* Encrypt a string.
*/
aes_encrypt(buf: Buffer): Buffer {
const c = Crypto.createCipher('aes192', this.secret);
const b1 = c.update(buf);
const b2 = c.final();
return Buffer.concat([b1, b2]);
}
/**
* Dencrypt a string.
*/
aes_decrypt(buf: Buffer ) {
try {
const c = Crypto.createDecipher('aes192', this.secret);
const b1 = c.update(buf);
const b2 = c.final();
return Buffer.concat([b1, b2]);
} catch (_) {
return new Buffer(0);
}
aesEncrypt(buf: Buffer): Buffer {
return aesEncrypt(buf, this.secret);
}
}

View file

@ -1,7 +1,8 @@
import {generateRandomHexString} from './crypto-utils';
const assert = require('assert');
const _ = require('lodash');
const Error = require('http-errors');
const Crypto = require('crypto');
const minimatch = require('minimatch');
const Utils = require('./utils');
@ -164,7 +165,7 @@ class Config {
// unique identifier of self server (or a cluster), used to avoid loops
if (!self.server_id) {
self.server_id = Crypto.pseudoRandomBytes(6).toString('hex');
self.server_id = generateRandomHexString(6);
}
}
@ -209,7 +210,7 @@ class Config {
}
// it generates a secret key
// FUTURE: this might be an external secret key, perhaps whitin config file?
this.secret = Crypto.pseudoRandomBytes(32).toString('hex');
this.secret = generateRandomHexString(32);
return this.secret;
}
}

43
src/lib/crypto-utils.js Normal file
View file

@ -0,0 +1,43 @@
// @flow
import {createDecipher, createCipher, createHash, pseudoRandomBytes} from 'crypto';
export const defaultAlgorithm = 'aes192';
export function aesEncrypt(buf: Buffer, secret: string): Buffer {
const c = createCipher(defaultAlgorithm, secret);
const b1 = c.update(buf);
const b2 = c.final();
return Buffer.concat([b1, b2]);
}
export function aesDecrypt(buf: Buffer, secret: string) {
try {
const c = createDecipher(defaultAlgorithm, secret);
const b1 = c.update(buf);
const b2 = c.final();
return Buffer.concat([b1, b2]);
} catch (_) {
return new Buffer(0);
}
}
export function createTarballHash() {
return createHash('sha1');
}
/**
* Express doesn't do etags with requests <= 1024b
* we use md5 here, it works well on 1k+ bytes, but sucks with fewer data
* could improve performance using crc32 after benchmarks.
* @param {Object} data
* @return {String}
*/
export function stringToMD5(data: Buffer | string) {
return createHash('md5').update(data).digest('hex');
}
export function generateRandomHexString(length: number = 8) {
return pseudoRandomBytes(length).toString('hex');
}

View file

@ -2,7 +2,6 @@
/* eslint prefer-rest-params: 0 */
import Crypto from 'crypto';
import assert from 'assert';
import fs from 'fs';
import Path from 'path';
@ -15,6 +14,7 @@ import {
generatePackageTemplate, normalizePackage, generateRevision, getLatestReadme, cleanUpReadme,
fileExist, noSuchFile, DEFAULT_REVISION, pkgFileName,
} from './storage-utils';
import {createTarballHash} from './crypto-utils';
import {loadPlugin} from '../lib/plugin-loader';
import LocalDatabase from '@verdaccio/local-storage';
import {UploadTarball, ReadTarball} from '@verdaccio/streams';
@ -386,7 +386,7 @@ class LocalStorage implements IStorage {
assert(validate_name(filename));
let length = 0;
const shaOneHash = Crypto.createHash('sha1');
const shaOneHash = createTarballHash();
const uploadStream: IUploadTarball = new UploadTarball();
const _transform = uploadStream._transform;
const storage = this._getLocalStorage(name);

View file

@ -1,9 +1,9 @@
// @flow
import _ from 'lodash';
import crypto from 'crypto';
import {ErrorCode, isObject, normalizeDistTags, DIST_TAGS} from './utils';
import Search from './search';
import {generateRandomHexString} from '../lib/crypto-utils';
import type {Package, Version} from '@verdaccio/types';
import type {IStorage} from '../../types';
@ -60,7 +60,7 @@ function normalizePackage(pkg: Package) {
function generateRevision(rev: string): string {
const _rev = rev.split('-');
return ((+_rev[0] || 0) + 1) + '-' + crypto.pseudoRandomBytes(8).toString('hex');
return ((+_rev[0] || 0) + 1) + '-' + generateRandomHexString();
}
function getLatestReadme(pkg: Package): string {

View file

@ -1,13 +1,5 @@
// @flow
import crypto from 'crypto';
export function spliceURL(...args: Array<string>): string {
return Array.from(args).reduce((lastResult, current) => lastResult + current).replace(/([^:])(\/)+(.)/g, `$1/$3`);
}
/**
* Get MD5 from string
*/
export function stringToMD5(string: string): string {
return crypto.createHash('md5').update(string).digest('hex');
}

View file

@ -1,5 +1,5 @@
// @flow
import {stringToMD5} from './string';
import {stringToMD5} from '../lib/crypto-utils';
export const GRAVATAR_DEFAULT = 'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mm';

View file

@ -23,7 +23,7 @@ export interface IAuth {
logger: Logger;
secret: string;
plugins: Array<any>;
aes_encrypt(buf: Buffer): Buffer;
aesEncrypt(buf: Buffer): Buffer;
apiJWTmiddleware(): $NextFunctionVer;
webUIJWTmiddleware(): $NextFunctionVer;
authenticate(user: string, password: string, cb: Callback): void;