Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ script:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then make check; fi || exit 1
- make lint || exit 1
- make unit-test || exit 1
- make cipher-test || exit 1
# Do not do code signing if it's a PR.
- if [[ "$TRAVIS_PULL_REQUEST" == true && "$TRAVIS_OS_NAME" == "osx" ]]; then
CSC_IDENTITY_AUTO_DISCOVERY=false make build-electron || exit 1;
Expand Down
3 changes: 0 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ unit-test: ## runs unit tests
cipher-test:
npm run cipher-test

cipher-test-extensive:
npm run cipher-test-extensive

run-docker: ## runs docker container
docker volume create skycoin-data
docker volume create skycoin-wallet
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ For security reasons, this wallet does not store the the seeds, neither in the b
maintain a backup of them. The seeds are also not transmitted anywhere outside the application code.

To maintain maximum compatibility with Skycoin's original code, the cryptographic functions used by this wallet are in the
[skycoin-lite](https://github.com/skycoin/skycoin-lite) repository, coded in Go (Golang), and are transpiled using gopherjs.
The transpiled code is in the [src/assets/scripts/main.js](/src/assets/scripts/main.js) file, in this repository.
[skycoin-lite](https://github.com/skycoin/skycoin-lite) repository, coded in Go (Golang), and are compiled to wasm.
The compiled wasm file is [src/assets/scripts/skycoin-lite.wasm](/src/assets/scripts/skycoin-lite.wasm).

The mnemonic phrases are created using the [bip39 library](https://www.npmjs.com/package/bip39). To create mnemonic phrases
with enough entropy, that library uses the [randombytes library](https://www.npmjs.com/package/randombytes), which uses
Expand Down
2 changes: 1 addition & 1 deletion e2e-prod/save-data.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('Save data', () => {
page.loadWallet().then(() => {
expect<any>(page.verifyIfShowingWalletsPage()).toEqual(true);

browser.get('#/wallets');
browser.get('#/wallets').then(() => browser.sleep(500));
expect<any>(page.verifyLocalStorage()).toEqual(null);
expect<any>(page.verifyIfShowingWalletsPage()).toEqual(false);
done();
Expand Down
2 changes: 1 addition & 1 deletion e2e-prod/save-data.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { browser, by, element, ElementFinder, ExpectedConditions } from 'protrac

export class SaveDataPage {
navigateTo() {
return browser.get('#/wizard/create');
return browser.get('#/wizard/create').then(() => browser.sleep(500));
}

selectLanguage() {
Expand Down
4 changes: 2 additions & 2 deletions e2e/onboarding-create.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('Onboarding Create', () => {
let page: OnboardingCreatePage;

beforeAll(() => {
browser.get('/');
browser.get('/').then(() => browser.sleep(500));

page = new OnboardingCreatePage();
page.navigateTo();
Expand Down Expand Up @@ -118,7 +118,7 @@ describe('Onboarding Create', () => {
});

it('should load wallet with correct address', done => {
browser.get('#/wizard');
browser.get('#/wizard').then(() => browser.sleep(500));
expect<any>(page.verifyLoadedWalletAddress()).toEqual(true);
done();
});
Expand Down
2 changes: 1 addition & 1 deletion e2e/onboarding-create.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { browser, by, element, ElementFinder, ExpectedConditions } from 'protrac

export class OnboardingCreatePage {
navigateTo() {
return browser.get('#/wizard/create');
return browser.get('#/wizard/create').then(() => browser.sleep(500));
}

getHeaderText() {
Expand Down
2 changes: 1 addition & 1 deletion e2e/send_sky.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('Send Sky', () => {
let walletPage: WalletsPage;

beforeAll(() => {
browser.get('/');
browser.get('/').then(() => browser.sleep(500));
browser.executeScript(
`window.localStorage.setItem(\'wallets\',
JSON.stringify([{"label":"Test wallet","addresses":
Expand Down
2 changes: 1 addition & 1 deletion e2e/send_sky.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { browser, by, element } from 'protractor';

export class SendSkyPage {
navigateTo() {
return browser.get('#/send');
return browser.get('#/send').then(() => browser.sleep(500));
}

getHeaderText() {
Expand Down
2 changes: 1 addition & 1 deletion e2e/transactions.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('Transactions', () => {
let page: TransactionsPage;

beforeAll(() => {
browser.get('/');
browser.get('/').then(() => browser.sleep(500));
browser.executeScript(
`window.localStorage.setItem(\'wallets\',
JSON.stringify([{"label":"Test wallet","addresses":
Expand Down
2 changes: 1 addition & 1 deletion e2e/transactions.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { browser, by, element } from 'protractor';

export class TransactionsPage {
navigateTo() {
return browser.get('#/history');
return browser.get('#/history').then(() => browser.sleep(500));
}

getHeaderText() {
Expand Down
2 changes: 1 addition & 1 deletion e2e/wallets.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('Wallets', () => {
let page: WalletsPage;

beforeAll(() => {
browser.get('/');
browser.get('/').then(() => browser.sleep(500));
browser.executeScript(
`window.localStorage.setItem(\'wallets\',
JSON.stringify([{"label":"Test wallet","addresses":
Expand Down
2 changes: 1 addition & 1 deletion e2e/wallets.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { browser, by, element, ExpectedConditions } from 'protractor';

export class WalletsPage {
navigateTo() {
return browser.get('#/wallets');
return browser.get('#/wallets').then(() => browser.sleep(500));
}

getHeaderText() {
Expand Down
13 changes: 6 additions & 7 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
// https://karma-runner.github.io/0.13/config/configuration-file.html

module.exports = function (config) {

var cipherParamIndex = process.argv.indexOf('--cipher');
// check if command line has cipher parameter with not empty value
if (cipherParamIndex > -1 && (cipherParamIndex + 1) < process.argv.length && process.argv[cipherParamIndex + 1]) {
var cipherMode = process.argv[cipherParamIndex + 1];

if (process.argv.indexOf('--cipher') > -1) {
var testCipher = true;
}

config.set({
Expand All @@ -21,11 +19,12 @@ module.exports = function (config) {
require('karma-read-json')
],
files: [
{ pattern: 'e2e/test-fixtures/*.json', included: false }
{ pattern: 'e2e/test-fixtures/*.json', included: false },
{ pattern: 'src/assets/scripts/wasm_exec.js', included: true }
],
client: {
// this works only with `karma start`, not `karma run`.
cipher: cipherMode,
cipher: testCipher,
args: ['--browserNoActivityTimeout', config.browserNoActivityTimeout],
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
"snyk-protect": "snyk protect",
"protractor": "protractor protractor.conf.js",
"test": "ng test -sm=false --watch=false --browsers ChromeHeadlessNoSandbox",
"cipher-test": "ng test -sm=false --watch=false --browsers ChromeHeadlessNoSandbox --browserNoActivityTimeout=180000 --cipher quick",
"cipher-test-extensive": "ng test -sm=false --watch=false --browsers ChromeHeadlessNoSandbox --browserNoActivityTimeout=180000 --cipher extensive",
"cipher-test": "ng test -sm=false --watch=false --browsers ChromeHeadlessNoSandbox --browserNoActivityTimeout=180000 --cipher",
"test:watch": "ng test -sm=false --browsers Chrome",
"prepare": "npm run snyk-protect",
"start-docker": "ng serve --proxy-config docker-proxy.config.js --delete-output-path false",
Expand Down
4 changes: 2 additions & 2 deletions src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div class="crypto-alert" *ngIf="!browserHasCryptoInsideWorkers">
<div class="crypto-alert" *ngIf="!browserCompatibleWithWasm || !wasmFileLoaded">
<div>
<mat-icon>error</mat-icon>
<div>{{ 'errors.crypto-no-available' | translate }}</div>
<div>{{ (!browserCompatibleWithWasm ? 'errors.wasm-no-available' : 'errors.wasm-not-downloaded') | translate }}</div>
</div>
</div>
<router-outlet></router-outlet>
7 changes: 4 additions & 3 deletions src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import { NO_ERRORS_SCHEMA, Renderer2 } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

import { AppComponent } from './app.component';
import { MockLanguageService, MockTranslatePipe, MockTranslateService, MockCustomMatDialogService } from './utils/test-mocks';
import { LanguageService } from './services/language.service';
import { CipherProvider } from './services/cipher.provider';
import { CipherProvider, InitializationResults } from './services/cipher.provider';
import { CustomMatDialogService } from './services/custom-mat-dialog.service';
import { Bip39WordListService } from './services/bip39-word-list.service';

Expand All @@ -24,7 +23,9 @@ describe('AppComponent', () => {
{ provide: LanguageService, useClass: MockLanguageService },
{ provide: TranslateService, useClass: MockTranslateService },
{ provide: Router, useValue: { events: Observable.of({}) } },
{ provide: CipherProvider, useValue: { browserHasCryptoInsideWorkers: new BehaviorSubject<boolean>(true) } },
{ provide: CipherProvider, useValue: {
initialize() { return Observable.of(InitializationResults.Ok); },
} },
{ provide: Renderer2, useValue: { addClass: null, removeClass: null } },
{ provide: CustomMatDialogService, useClass: MockCustomMatDialogService },
{ provide: Bip39WordListService, useValue: {} }
Expand Down
24 changes: 19 additions & 5 deletions src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core';

import { config } from './app.config';
import { environment } from '../environments/environment';
import { CipherProvider } from './services/cipher.provider';
import { CipherProvider, InitializationResults } from './services/cipher.provider';
import { CustomMatDialogService } from './services/custom-mat-dialog.service';
import { Bip39WordListService } from './services/bip39-word-list.service';

Expand All @@ -19,7 +19,8 @@ export class AppComponent implements OnInit {
highest: number;
otcEnabled: boolean;
version: string;
browserHasCryptoInsideWorkers: boolean;
browserCompatibleWithWasm = true;
wasmFileLoaded = true;

constructor(
private languageService: LanguageService,
Expand All @@ -35,9 +36,9 @@ export class AppComponent implements OnInit {
}
});

cipherProvider.browserHasCryptoInsideWorkers.subscribe(value => {
this.browserHasCryptoInsideWorkers = value;
});
cipherProvider.initialize().subscribe(response => {
this.checkCipherProviderResponse(response);
}, response => this.checkCipherProviderResponse(response));

dialog.showingDialog.subscribe(value => {
if (!value) {
Expand All @@ -63,4 +64,17 @@ export class AppComponent implements OnInit {
loading() {
return !this.current || !this.highest || this.current !== this.highest;
}

private checkCipherProviderResponse(response) {
if (window['removeSplash']) {
setTimeout(() => window['removeSplash']());
}
if (response !== InitializationResults.Ok) {
if (response === InitializationResults.ErrorLoadingWasmFile) {
this.wasmFileLoaded = false;
} else {
this.browserCompatibleWithWasm = false;
}
}
}
}
53 changes: 29 additions & 24 deletions src/app/services/cipher.provider.lib.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import '../../assets/scripts/main.js';
import { readJSON } from 'karma-read-json';

import { testCases } from '../utils/jasmine-utils';
import { Address } from '../app.datatypes';
import { convertAsciiToHexa } from '../utils/converters';
import { GenerateAddressResponse } from './cipher.provider.js';

declare var CipherExtras;
declare var Cipher;
declare var Go: any;

describe('CipherProvider Lib', () => {
const fixturesPath = 'e2e/test-fixtures/';
Expand All @@ -21,11 +19,18 @@ describe('CipherProvider Lib', () => {
'seed-0009.json', 'seed-0010.json'
];

const extensiveMode = 'extensive';
const testSettings = { addressCount: 1000, seedFilesCount: 11 };

const testSettings = process.argv.length > 0 && process.argv[0] === extensiveMode
? { addressCount: 1000, seedFilesCount: 11 }
: { addressCount: 30, seedFilesCount: 2 };
describe('Initialization', () => {
it('should be initialized', done => {
const go = new Go();
window['WebAssembly'].instantiateStreaming(fetch('/assets/scripts/skycoin-lite.wasm'), go.importObject).then((result) => {
go.run(result.instance);

done();
});
});
});

describe('generate address', () => {
const addressFixtureFile = readJSON(fixturesPath + addressesFileName);
Expand Down Expand Up @@ -97,31 +102,31 @@ describe('CipherProvider Lib', () => {

it(`should verify signature correctly`, done => {
testData.forEach(data => {
const result = CipherExtras.VerifySignature(data.public_key, data.signature, data.hash);
expect(result).toBeUndefined();
const result = window['SkycoinCipherExtras'].verifyPubKeySignedHash(data.public_key, data.signature, data.hash);
expect(result).toBeNull();
done();
});
});

it(`should check signature correctly`, done => {
testData.forEach(data => {
const result = CipherExtras.ChkSig(data.address, data.hash, data.signature);
expect(result).toBeUndefined();
const result = window['SkycoinCipherExtras'].verifyAddressSignedHash(data.address, data.signature, data.hash);
expect(result).toBeNull();
done();
});
});

it(`should verify signed hash correctly`, done => {
testData.forEach(data => {
const result = CipherExtras.VerifySignedHash(data.signature, data.hash);
expect(result).toBeUndefined();
const result = window['SkycoinCipherExtras'].verifySignatureRecoverPubKey(data.signature, data.hash);
expect(result).toBeNull();
done();
});
});

it(`should generate public key correctly`, done => {
testData.forEach(data => {
const pubKey = CipherExtras.PubKeyFromSig(data.signature, data.hash);
const pubKey = window['SkycoinCipherExtras'].pubKeyFromSig(data.signature, data.hash);
expect(pubKey).toBeTruthy();
expect(pubKey === data.public_key).toBeTruthy();
done();
Expand All @@ -130,7 +135,7 @@ describe('CipherProvider Lib', () => {

it(`sign hash should be created`, done => {
testData.forEach(data => {
const sig = CipherExtras.SignHash(data.hash, data.secret_key);
const sig = window['SkycoinCipherExtras'].signHash(data.hash, data.secret_key);
expect(sig).toBeTruthy();
done();
});
Expand Down Expand Up @@ -168,25 +173,25 @@ function generateAddresses(seed: string, keys: any[]): Address[] {
}

function generateAddress(seed: string): GenerateAddressResponse {
const address = Cipher.GenerateAddresses(seed);
const address = window['SkycoinCipher'].generateAddress(seed);
return {
address: {
address: address.Address,
public_key: address.Public,
secret_key: address.Secret
address: address.address,
public_key: address.public,
secret_key: address.secret
},
nextSeed: address.NextSeed
nextSeed: address.nextSeed
};
}

function verifyAddress(address) {
const addressFromPubKey = CipherExtras.AddressFromPubKey(address.public_key);
const addressFromSecKey = CipherExtras.AddressFromSecKey(address.secret_key);
const addressFromPubKey = window['SkycoinCipherExtras'].addressFromPubKey(address.public_key);
const addressFromSecKey = window['SkycoinCipherExtras'].addressFromSecKey(address.secret_key);

expect(addressFromPubKey && addressFromSecKey && addressFromPubKey === addressFromSecKey).toBe(true);

expect(CipherExtras.VerifySeckey(address.secret_key)).toBe(1);
expect(CipherExtras.VerifyPubkey(address.public_key)).toBe(1);
expect(window['SkycoinCipherExtras'].verifySeckey(address.secret_key)).toBe(null);
expect(window['SkycoinCipherExtras'].verifyPubkey(address.public_key)).toBe(null);
}

function verifyAddresses(addresses) {
Expand Down
Loading