kzwang/node-git-lfs

View on GitHub
lib/authenticator/basic.js

Summary

Maintainability
A
0 mins
Test Coverage
'use strict';

var _ = require('lodash');
var fs = require('fs');
var crypto = require('crypto');
var ssh_utils = require('ssh2').utils;

var Authenticator = require('./');

/**
 * RegExp for basic auth credentials
 *
 * credentials = auth-scheme 1*SP token68
 * auth-scheme = "Basic" ; case insensitive
 * token68     = 1*( ALPHA / DIGIT / "-" / "." / "_" / "~" / "+" / "/" ) *"="
 * @private
 */
const CREDENTIALS_REG_EXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9\-\._~\+\/]+=*) *$/;


/**
 * RegExp for basic auth user/pass
 *
 * user-pass   = userid ":" password
 * userid      = *<TEXT excluding ":">
 * password    = *TEXT
 * @private
 */
const USER_PASS_REG_EXP = /^([^:]*):(.*)$/;


class Credentials {
    constructor(username, password) {
        this.username = username;
        this.password = password;
    }
}

class BasicAuthenticator extends Authenticator {

    /**
     * Construct BasicAuthenticator instance
     * @param {Object} options, optional
     */
    constructor(options) {
        super();
        this._options = options || {};
        var clientPublicKeyPath = _.get(options, 'client_public_key');
        if (clientPublicKeyPath) {
            this.clientPublicKey = ssh_utils.genPublicKey(ssh_utils.parseKey(fs.readFileSync(clientPublicKeyPath)));
        }
    }

    canRead(user, repo, authorization) {
        var self = this;
        return new Promise(function(resolve, reject) {
            var credential = BasicAuthenticator._getCredential(authorization) || {};
            resolve(self._options.username === credential.username && self._options.password === credential.password);
        });
    }

    canWrite(user, repo, authorization) {
        return this.canRead(user, repo, authorization);
    }

    checkSSHAuthorization(publicAlgo, publicData, signAlgo, blob, signature){
        var self = this;
        return new Promise(function(resolve, reject) {
            if (!self.clientPublicKey) {
                return resolve();
            }

            var verifier = crypto.createVerify(signAlgo);
            verifier.update(blob);
            if (verifier.verify(self.clientPublicKey.publicOrig, signature, 'binary')){
                var encodedUserPass = new Buffer(self._options.username + ':' + self._options.password).toString('base64');
                return resolve(`Basic ${encodedUserPass}`);
            } else {
                return resolve();
            }

        });

    }

    static _getCredential(authorization) {
        var match = CREDENTIALS_REG_EXP.exec(authorization || '');

        if (!match) {
            return;
        }

        var userPass = USER_PASS_REG_EXP.exec(BasicAuthenticator._decodeBase64(match[1]));

        if (!userPass) {
            return;
        }

        return new Credentials(userPass[1], userPass[2]);
    }

    static _decodeBase64(str) {
        return new Buffer(str, 'base64').toString();
    }

}

module.exports = BasicAuthenticator;