Skip to content

Commit

Permalink
Fix compatibility with API v3
Browse files Browse the repository at this point in the history
  • Loading branch information
stripthis committed May 3, 2021
1 parent 9c507dd commit a184f0d
Show file tree
Hide file tree
Showing 26 changed files with 2,419 additions and 386 deletions.
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,26 @@
/_/ \__,_/____/____/_.___/\____/_/\__/

Open source password manager for teams
(c) 2020 Passbolt SA
(c) 2021 Passbolt SA

## License

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Passbolt - Open source password manager for teams

This program is distributed in the hope that it will be useful,
but without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose. See the
GNU Affero General Public License for more details.
(c) 2021 Passbolt SA

[Affero General Public License v3](http://www.gnu.org/licenses/agpl-3.0.html)
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
Public License (AGPL) as published by the Free Software Foundation version 3.

The name "Passbolt" is a registered trademark of Passbolt SA, and Passbolt SA hereby declines to grant a trademark
license to "Passbolt" pursuant to the GNU Affero General Public License version 3 Section 7(e), without a separate
agreement with Passbolt SA.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not,
see [GNU Affero General Public License v3](http://www.gnu.org/licenses/agpl-3.0.html).

# What is the purpose of this repository

Expand Down
9 changes: 4 additions & 5 deletions app/controllers/appController.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
*/
const i18n = require('../models/i18n.js');
const GpgAuthController = require('./gpgAuthController.js');
const validate = require('validator');

Expand All @@ -28,15 +27,15 @@ class AppController extends GpgAuthController {
* App controllers should not be instanciated without a name
*/
getName() {
throw new Error(i18n.__('Error: no controller name set'));
throw new Error('Error: no controller name set');
}

/**
* Index Action - Find and filter
* @returns {Promise<*>}
*/
async index() {
const url = `${this.URL_BASE}.json?api-version=v1`;
const url = `${this.URL_BASE}.json?api-version=v2`;
const request = {
url,
jar: this.cookieJar
Expand All @@ -58,11 +57,11 @@ class AppController extends GpgAuthController {
async view(id, options) {
// Check if this is a valid UUID
if (!validate.isUUID(id)) {
this.error(i18n.__(`This is not a valid UUID: ${id}`));
this.error(`This is not a valid UUID: ${id}`);
}

// Get the record
let url = `${this.URL_BASE}/${id}.json?api-version=v1&`;
let url = `${this.URL_BASE}/${id}.json?api-version=v2&`;
if (typeof options !== 'undefined') {
url += options;
}
Expand Down
16 changes: 9 additions & 7 deletions app/controllers/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
*/
const i18n = require('../models/i18n.js');
const Config = require('../models/config.js');

class Controller {
Expand All @@ -20,7 +19,7 @@ class Controller {
*/
constructor(program) {
this._request = require('request');
this._verbose = (program !== undefined && program.verbose !== undefined && program.verbose);
this._verbose = (program && program.opts() && program.opts().verbose);
const config = Config.get();
this._agentOptions = config.agentOptions;
}
Expand Down Expand Up @@ -53,11 +52,11 @@ class Controller {
resolve(result);
})
.on('error', () => {
const err = new Error(i18n.__('Error: could not connect to ') + options.url);
const err = new Error(`Error: could not connect to ${options.url}`);
reject(err);
});
} catch (error) {
const err = new Error(i18n.__('Error: could not connect to ') + options.url);
const err = new Error(`Error: could not connect to ${options.url}`);
reject(err);
}
});
Expand Down Expand Up @@ -91,11 +90,11 @@ class Controller {
resolve(result);
})
.on('error', () => {
const err = new Error(i18n.__('Error: could not connect to ') + options.url);
const err = new Error(`Error: could not connect to ${options.url}`);
reject(err);
});
} catch (error) {
const err = new Error(i18n.__('Error: could not connect to ') + options.url);
const err = new Error(`Error: could not connect to ${options.url}`);
reject(err);
}
});
Expand All @@ -119,6 +118,9 @@ class Controller {
error(error) {
if (error instanceof Error) {
this.log(error.message);
if (this._verbose) {
this.log(error);
}
} else if (typeof error === 'string') {
this.log(error);
} else {
Expand All @@ -140,7 +142,7 @@ class Controller {
body = JSON.parse(response.body);
} catch (syntaxError) {
this.log(response.body.toString(), 'verbose');
this.error(`${i18n.__('Error')} ${response.statusCode} ${i18n.__('could not parse server response.')}`);
this.error(`'Error ${response.statusCode} could not parse server response.`);
return;
}
return body;
Expand Down
24 changes: 12 additions & 12 deletions app/controllers/gpgAuthController.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ const CookieStore = require('tough-cookie-file-store');
const Crypto = require('../models/crypto.js');
const GpgAuthToken = require('../models/gpgAuthToken.js');
const GpgAuthHeader = require('../models/gpgAuthHeader.js');
const i18n = require('../models/i18n.js');
const path = require('path');
const User = require('../models/user.js');

Expand Down Expand Up @@ -44,7 +43,7 @@ class GpgAuthController extends MfaController {
// URLs
const baseUrl = `${this.domain.url}/auth`;
this.URL_VERIFY = `${baseUrl}/verify.json`;
this.URL_CHECKSESSION = `${baseUrl}/checkSession.json`;
this.URL_CHECKSESSION = `${baseUrl}/is-authenticated.json`;
this.URL_LOGIN = `${baseUrl}/login.json`;
this.URL_LOGOUT = `${baseUrl}/logout`;

Expand Down Expand Up @@ -132,12 +131,12 @@ class GpgAuthController extends MfaController {

async getCsrfToken() {
return new Promise((resolve, reject) => {
const domain = new URL(this.domain.url).host;
const domain = new URL(this.domain.url).hostname;
const path = '/';
const key = 'csrfToken';

this.cookieStore.findCookie(domain, path, key, (error, cookie) => {
if (cookie === null) {
if (!cookie) {
reject();
} else {
resolve(cookie.value);
Expand Down Expand Up @@ -268,21 +267,22 @@ class GpgAuthController extends MfaController {
_serverResponseHealthCheck(step, response) {
// Check if the HTTP status is OK
if (response.statusCode !== 200) {
throw new Error(`${i18n.__('There was a problem when trying to communicate with the server')
} (HTTP Code:${response.status})`);
throw new Error(`There was a problem when trying to communicate with the server (HTTP Code:${response.status})`);
}

// Check if there is GPGAuth error flagged by the server
if (response.headers['x-gpgauth-error']) {
throw new Error(i18n.__('The server rejected the verification request.') + response.headers['x-gpgauth-debug']);
if (step !== 'logout') {
if (response.headers['x-gpgauth-error']) {
throw new Error(`The server rejected the verification request ${response.headers['x-gpgauth-debug']}`);
}
}

// Check if the headers are correct
try {
GpgAuthHeader.validateByStage(step, response.headers);
} catch (error) {
this.log(error.message, 'verbose');
throw new Error(i18n.__('The server was unable to respect the authentication protocol.'));
throw new Error('The server was unable to respect the authentication protocol.');
}

return true;
Expand All @@ -302,11 +302,11 @@ class GpgAuthController extends MfaController {
GpgAuthToken.validate('token', token);
} catch (error) {
console.log(error.message, 'verbose');
throw new Error(i18n.__('Error: GPGAuth verify step failed. Maybe your user does not exist or have been deleted.'));
throw new Error('Error: GPGAuth verify step failed. Maybe your user does not exist or have been deleted.');
}

if (!this.token || token !== this.token) {
throw new Error(i18n.__('Error: The server was unable to identify. GPGAuth tokens do not match.'));
throw new Error('Error: The server was unable to identify. GPGAuth tokens do not match.');
}
return response;
}
Expand Down Expand Up @@ -371,7 +371,7 @@ class GpgAuthController extends MfaController {
body = JSON.parse(response.body);
} catch (syntaxError) {
this.log(response.body.toString(), 'verbose');
this.error(`${i18n.__('Error')} ${response.statusCode} ${i18n.__('could not parse server response.')}`);
this.error(`Error ${response.statusCode} could not parse server response.`);
return;
}
return body;
Expand Down
22 changes: 11 additions & 11 deletions app/controllers/mfaController.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
const CliController = require('./cliController.js');
const Domain = require('../models/domain.js');
const Config = require('../models/config.js');
const i18n = require('../models/i18n.js');

class MfaController extends CliController {
/**
Expand Down Expand Up @@ -76,7 +75,7 @@ class MfaController extends CliController {

if (response.statusCode !== 200) {
this.log(JSON.parse(response.body), 'verbose');
const msg = `${i18n.__('There was a problem with MFA authentication.')} (HTTP Code:${response.statusCode})\n`;
const msg = `There was a problem with MFA authentication. (HTTP Code:${response.statusCode})`;
this.error(msg);
}
}
Expand All @@ -102,7 +101,8 @@ class MfaController extends CliController {
}
}
if (!provider) {
const msg = i18n.__('No supported MFA provider found in config. Please setup an additional provider using passbolt web client.');
const msg = 'No supported MFA provider found in config.' +
' Please setup an additional provider using passbolt web client.';
throw new Error(msg);
}
return provider;
Expand All @@ -121,11 +121,11 @@ class MfaController extends CliController {
} else {
userProviders = config.mfa.providers;
if (!Array.isArray(userProviders) || userProviders.length === 0) {
const msg = i18n.__('No supported MFA provider found in user config. Please setup MFA provider preferences.');
const msg = 'No supported MFA provider found in user config. Please setup MFA provider preferences.';
this.error(msg);
}
if (userProviders.length === 1 && userProviders[0].toLowerCase() === 'duo') {
const msg = i18n.__('Duo is not a supported MFA provider. Please edit MFA provider preferences to include more providers.');
const msg ='Duo is not a supported MFA provider. Please edit MFA provider preferences to include more providers.';
this.error(msg);
}
for (let i = 0; i < userProviders.length; i++) {
Expand All @@ -150,7 +150,7 @@ class MfaController extends CliController {
url = this.URL_MFA_VERIFY_TOTP;
break;
default:
this.error(i18n.__(`MFA provider not supported: ${this.provider}`));
this.error(`MFA provider not supported: ${this.provider}`);
}
return url;
}
Expand All @@ -171,7 +171,7 @@ class MfaController extends CliController {
data = {'totp': otp};
break;
default:
this.error(i18n.__(`MFA provider not supported: ${this.provider}`));
this.error(`MFA provider not supported: ${this.provider}`);
}
return data;
}
Expand Down Expand Up @@ -203,9 +203,9 @@ class MfaController extends CliController {
const input = await this.prompt({
properties: {
otp: {
description: i18n.__('Please enter the one time password displayed on your tablet or phone.\notp'),
description: 'Please enter the one time password displayed on your tablet or phone.\notp',
pattern: /^[0-9]{6}$/,
message: i18n.__('One time password must be a six digit number.'),
message: 'One time password must be a six digit number.',
required: true
}
}
Expand All @@ -222,9 +222,9 @@ class MfaController extends CliController {
const input = await this.prompt({
properties: {
otp: {
description: i18n.__('Plug in your yubikey and put your finger on it.\notp'),
description: 'Plug in your yubikey and put your finger on it.\notp',
pattern: /^[cbdefghijklnrtuv]{44}$/,
message: i18n.__('Yubikey OTP must be a ModHex compatible 44 characters in length string.'),
message: 'Yubikey OTP must be a ModHex compatible 44 characters in length string.',
required: true,
hidden: true
}
Expand Down
15 changes: 7 additions & 8 deletions app/models/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ const Config = require('./config');
const Gpg = require('gpg');
const XRegExp = require('xregexp');
const jsSHA = require('jssha');
const randomBytes = require('crypto').randomBytes;
const StringDecoder = require('string_decoder').StringDecoder;
const {randomBytes} = require('crypto');
const {StringDecoder} = require('string_decoder');

class Crypto {
/**
Expand Down Expand Up @@ -75,7 +75,7 @@ class Crypto {
* @returns {Promise}
*/
static encrypt(recipient, msg) {
const promise = new Promise(((resolve, reject) => {
return new Promise(((resolve, reject) => {
const p = {
resolve,
reject
Expand All @@ -90,37 +90,36 @@ class Crypto {
}
}
Gpg.encrypt(msg, options, (error, buffer) => {
if (error != undefined) {
if (error) {
return p.reject(error);
}
const decoder = new StringDecoder('utf8');
return p.resolve(decoder.write(buffer));
});
}));
return promise;
}


/**
* Decrypt a msg with a given key
* @param msg string message to decrypt
* @param options
* @returns {Promise}
*/
static decrypt(msg, options) {
const promise = new Promise(((resolve, reject) => {
return new Promise(((resolve, reject) => {
const p = {
resolve,
reject
};

Gpg.decrypt(msg, options, (error, decrypted) => {
if (error != undefined) {
if (error) {
return p.reject(error);
}
return p.resolve(decrypted.toString('utf8'));
});
}));
return promise;
}
}

Expand Down
Loading

0 comments on commit a184f0d

Please sign in to comment.