Commit 3a206f7a authored by nopara73's avatar nopara73

Merge branch 'master' into documentation

# Conflicts:
#	Breeze.Documentation/ApiSpecification.md
parents 2f5365de b32ce1f4
...@@ -238,6 +238,44 @@ ModelManifest.xml ...@@ -238,6 +238,44 @@ ModelManifest.xml
# Paket dependency manager # Paket dependency manager
.paket/paket.exe .paket/paket.exe
# UI ignores
# compiled output
**/dist
**/tmp
**/build
# dependencies
**/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
**/.sass-cache
**/connect.lock
**/coverage/*
**/libpeerconnection.log
npm-debug.log
testem.log
**/typings
# e2e
**/e2e/*.js
**/e2e/*.map
#System Files
.DS_Store
Thumbs.db
# ORIGINAL .gitignore STARTS HERE # ORIGINAL .gitignore STARTS HERE
......
This diff is collapsed.
...@@ -13,15 +13,15 @@ namespace Breeze.Api.Tests ...@@ -13,15 +13,15 @@ namespace Breeze.Api.Tests
public class ControllersTests public class ControllersTests
{ {
[Fact] [Fact]
public void CreateSafeSuccessfullyReturnsMnemonic() public void CreateWalletSuccessfullyReturnsMnemonic()
{ {
var mockSafeCreate = new Mock<ISafeWrapper>(); var mockWalletCreate = new Mock<IWalletWrapper>();
mockSafeCreate.Setup(safe => safe.Create(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns("mnemonic"); mockWalletCreate.Setup(wallet => wallet.Create(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns("mnemonic");
var controller = new SafeController(mockSafeCreate.Object); var controller = new WalletController(mockWalletCreate.Object);
// Act // Act
var result = controller.Create(new SafeCreationModel var result = controller.Create(new WalletCreationModel
{ {
Name = "myName", Name = "myName",
FolderPath = "", FolderPath = "",
...@@ -30,29 +30,29 @@ namespace Breeze.Api.Tests ...@@ -30,29 +30,29 @@ namespace Breeze.Api.Tests
}); });
// Assert // Assert
mockSafeCreate.VerifyAll(); mockWalletCreate.VerifyAll();
var viewResult = Assert.IsType<JsonResult>(result); var viewResult = Assert.IsType<JsonResult>(result);
Assert.Equal("mnemonic", viewResult.Value); Assert.Equal("mnemonic", viewResult.Value);
Assert.NotNull(result); Assert.NotNull(result);
} }
[Fact] [Fact]
public void LoadSafeSuccessfullyReturnsSafeModel() public void LoadWalletSuccessfullyReturnsWalletModel()
{ {
SafeModel safeModel = new SafeModel WalletModel walletModel = new WalletModel
{ {
FileName = "myWallet", FileName = "myWallet",
Network = "MainNet", Network = "MainNet",
Addresses = new List<string> { "address1", "address2", "address3", "address4", "address5" } Addresses = new List<string> { "address1", "address2", "address3", "address4", "address5" }
}; };
var mockSafeWrapper = new Mock<ISafeWrapper>(); var mockWalletWrapper = new Mock<IWalletWrapper>();
mockSafeWrapper.Setup(safe => safe.Recover(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(safeModel); mockWalletWrapper.Setup(wallet => wallet.Recover(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(walletModel);
var controller = new SafeController(mockSafeWrapper.Object); var controller = new WalletController(mockWalletWrapper.Object);
// Act // Act
var result = controller.Recover(new SafeRecoveryModel var result = controller.Recover(new WalletRecoveryModel
{ {
Name = "myName", Name = "myName",
FolderPath = "", FolderPath = "",
...@@ -62,32 +62,32 @@ namespace Breeze.Api.Tests ...@@ -62,32 +62,32 @@ namespace Breeze.Api.Tests
}); });
// Assert // Assert
mockSafeWrapper.VerifyAll(); mockWalletWrapper.VerifyAll();
var viewResult = Assert.IsType<JsonResult>(result); var viewResult = Assert.IsType<JsonResult>(result);
Assert.NotNull(viewResult.Value); Assert.NotNull(viewResult.Value);
Assert.IsType<SafeModel>(viewResult.Value); Assert.IsType<WalletModel>(viewResult.Value);
var model = viewResult.Value as SafeModel; var model = viewResult.Value as WalletModel;
Assert.Equal("myWallet", model.FileName); Assert.Equal("myWallet", model.FileName);
} }
[Fact] [Fact]
public void RecoverSafeSuccessfullyReturnsSafeModel() public void RecoverWalletSuccessfullyReturnsWalletModel()
{ {
SafeModel safeModel = new SafeModel WalletModel walletModel = new WalletModel
{ {
FileName = "myWallet", FileName = "myWallet",
Network = "MainNet", Network = "MainNet",
Addresses = new List<string> { "address1", "address2", "address3", "address4", "address5" } Addresses = new List<string> { "address1", "address2", "address3", "address4", "address5" }
}; };
var mockSafeWrapper = new Mock<ISafeWrapper>(); var mockWalletWrapper = new Mock<IWalletWrapper>();
mockSafeWrapper.Setup(safe => safe.Load(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(safeModel); mockWalletWrapper.Setup(wallet => wallet.Load(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(walletModel);
var controller = new SafeController(mockSafeWrapper.Object); var controller = new WalletController(mockWalletWrapper.Object);
// Act // Act
var result = controller.Load(new SafeLoadModel var result = controller.Load(new WalletLoadModel
{ {
Name = "myName", Name = "myName",
FolderPath = "", FolderPath = "",
...@@ -95,25 +95,25 @@ namespace Breeze.Api.Tests ...@@ -95,25 +95,25 @@ namespace Breeze.Api.Tests
}); });
// Assert // Assert
mockSafeWrapper.VerifyAll(); mockWalletWrapper.VerifyAll();
var viewResult = Assert.IsType<JsonResult>(result); var viewResult = Assert.IsType<JsonResult>(result);
Assert.NotNull(viewResult.Value); Assert.NotNull(viewResult.Value);
Assert.IsType<SafeModel>(viewResult.Value); Assert.IsType<WalletModel>(viewResult.Value);
var model = viewResult.Value as SafeModel; var model = viewResult.Value as WalletModel;
Assert.Equal("myWallet", model.FileName); Assert.Equal("myWallet", model.FileName);
} }
[Fact] [Fact]
public void FileNotFoundExceptionandReturns404() public void FileNotFoundExceptionandReturns404()
{ {
var mockSafeWrapper = new Mock<ISafeWrapper>(); var mockWalletWrapper = new Mock<IWalletWrapper>();
mockSafeWrapper.Setup(safe => safe.Load(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Throws<FileNotFoundException>(); mockWalletWrapper.Setup(wallet => wallet.Load(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Throws<FileNotFoundException>();
var controller = new SafeController(mockSafeWrapper.Object); var controller = new WalletController(mockWalletWrapper.Object);
// Act // Act
var result = controller.Load(new SafeLoadModel var result = controller.Load(new WalletLoadModel
{ {
Name = "myName", Name = "myName",
FolderPath = "", FolderPath = "",
...@@ -121,7 +121,7 @@ namespace Breeze.Api.Tests ...@@ -121,7 +121,7 @@ namespace Breeze.Api.Tests
}); });
// Assert // Assert
mockSafeWrapper.VerifyAll(); mockWalletWrapper.VerifyAll();
var viewResult = Assert.IsType<ObjectResult>(result); var viewResult = Assert.IsType<ObjectResult>(result);
Assert.NotNull(viewResult); Assert.NotNull(viewResult);
Assert.Equal(404, viewResult.StatusCode); Assert.Equal(404, viewResult.StatusCode);
......
{ {
"variables": [], "variables": [],
"info": { "info": {
"name": "Safe", "name": "Wallet",
"_postman_id": "11f915f1-7aac-bfeb-000c-b66348f4636f", "_postman_id": "11f915f1-7aac-bfeb-000c-b66348f4636f",
"description": "Requests relating to operations on the safe", "description": "Requests relating to operations on the wallet",
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"
}, },
"item": [ "item": [
{ {
"name": "Create safe - success", "name": "Create wallet - success",
"request": { "request": {
"url": "http://localhost:5000/api/safe/", "url": "http://localhost:5000/api/v1/wallet/",
"method": "POST", "method": "POST",
"header": [ "header": [
{ {
...@@ -28,9 +28,9 @@ ...@@ -28,9 +28,9 @@
"response": [] "response": []
}, },
{ {
"name": "Create safe - validation errors", "name": "Create wallet - validation errors",
"request": { "request": {
"url": "http://localhost:5000/api/safe/", "url": "http://localhost:5000/api/v1/wallet/",
"method": "POST", "method": "POST",
"header": [ "header": [
{ {
...@@ -48,9 +48,9 @@ ...@@ -48,9 +48,9 @@
"response": [] "response": []
}, },
{ {
"name": "Load safe", "name": "Load wallet",
"request": { "request": {
"url": "http://localhost:5000/api/safe/?password=123456&folderPath=MyWallets&name=myFirstWallet", "url": "http://localhost:5000/api/v1/wallet/?password=123456&folderPath=MyWallets&name=myFirstWallet",
"method": "GET", "method": "GET",
"header": [ "header": [
{ {
...@@ -68,9 +68,9 @@ ...@@ -68,9 +68,9 @@
"response": [] "response": []
}, },
{ {
"name": "Recover safe", "name": "Recover wallet",
"request": { "request": {
"url": "http://localhost:5000/api/safe/recover", "url": "http://localhost:5000/api/v1/wallet/recover",
"method": "POST", "method": "POST",
"header": [ "header": [
{ {
......
...@@ -2,19 +2,15 @@ ...@@ -2,19 +2,15 @@
namespace Breeze.Api.Controllers namespace Breeze.Api.Controllers
{ {
[Route("api/[controller]")]
[Route("api/v{version:apiVersion}/[controller]")]
public class NodeController : Controller public class NodeController : Controller
{ {
[Route("connect")] [HttpGet]
public IActionResult Connect(string[] args)
{
return NotFound();
}
[Route("status")] [Route("status")]
public IActionResult Status() public IActionResult Status()
{ {
return this.NotFound(); return this.NotFound();
} }
} }
} }
\ No newline at end of file
using Microsoft.AspNetCore.Builder; using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Swashbuckle.AspNetCore.Swagger;
namespace Breeze.Api namespace Breeze.Api
{ {
...@@ -28,6 +31,31 @@ namespace Breeze.Api ...@@ -28,6 +31,31 @@ namespace Breeze.Api
// add serializers for NBitcoin objects // add serializers for NBitcoin objects
.AddJsonOptions(options => NBitcoin.JsonConverters.Serializer.RegisterFrontConverters(options.SerializerSettings)) .AddJsonOptions(options => NBitcoin.JsonConverters.Serializer.RegisterFrontConverters(options.SerializerSettings))
.AddControllers(services); .AddControllers(services);
services.AddApiVersioning(options =>
{
options.DefaultApiVersion = new ApiVersion(1, 0);
});
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(setup =>
{
setup.SwaggerDoc("v1", new Info { Title = "Breeze.Api", Version = "v1" });
// FIXME: prepopulates the version in the URL of the Swagger UI found at http://localhost:5000/swagger
// temporary needed until Swashbuckle supports it out-of-the-box
setup.DocInclusionPredicate((version, apiDescription) =>
{
apiDescription.RelativePath = apiDescription.RelativePath.Replace("v{version}", version);
var versionParameter = apiDescription.ParameterDescriptions.SingleOrDefault(p => p.Name == "version");
if (versionParameter != null)
{
apiDescription.ParameterDescriptions.Remove(versionParameter);
}
return true;
});
});
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
...@@ -37,6 +65,15 @@ namespace Breeze.Api ...@@ -37,6 +65,15 @@ namespace Breeze.Api
loggerFactory.AddDebug(); loggerFactory.AddDebug();
app.UseMvc(); app.UseMvc();
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Breeze.Api V1");
});
} }
} }
} }
{ {
"dependencies": { "dependencies": {
"Microsoft.AspNetCore.Mvc": "1.1.2", "Microsoft.AspNetCore.Mvc": "1.1.2",
"Microsoft.AspNetCore.Mvc.Versioning": "1.0.3",
"Microsoft.AspNetCore.Routing": "1.1.1", "Microsoft.AspNetCore.Routing": "1.1.1",
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.1", "Microsoft.AspNetCore.Server.IISIntegration": "1.1.1",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.1", "Microsoft.AspNetCore.Server.Kestrel": "1.1.1",
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
"Microsoft.NETCore.App": "1.1.0", "Microsoft.NETCore.App": "1.1.0",
"NBitcoin": "3.0.2.10", "NBitcoin": "3.0.2.10",
"Stratis.Bitcoin": "1.0.1.2-alpha", "Stratis.Bitcoin": "1.0.1.2-alpha",
"Swashbuckle.AspNetCore": "1.0.0-rc3",
"System.Reactive": "3.1.1", "System.Reactive": "3.1.1",
"System.Runtime.Loader": "4.3.0" "System.Runtime.Loader": "4.3.0"
}, },
......
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
DEBUG=true
HOST=http://localhost:4200
# Breeze-UI
Graphical User Interface for Stratis Breeze Wallet.
{
"project": {
"name": "breeze-ui"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.json",
"prefix": "app",
"styles": [
"../node_modules/bootstrap/dist/css/bootstrap.min.css",
"styles.css"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"files": "src/**/*.ts",
"project": "src/tsconfig.json"
},
{
"files": "e2e/**/*.ts",
"project": "e2e/tsconfig.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"prefixInterfaces": false,
"inline": {
"style": false,
"template": false
},
"spec": {
"class": false,
"component": true,
"directive": true,
"module": false,
"pipe": true,
"service": true
}
}
}
import { BreezeUIPage } from './app.po';
describe('breeze-ui App', function() {
let page: BreezeUIPage;
beforeEach(() => {
page = new BreezeUIPage();
});
it('should display message saying app works', () => {
page.navigateTo();
expect(page.getParagraphText()).toEqual('app works!');
});
});
import { browser, element, by } from 'protractor';
export class BreezeUIPage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
}
{
"compileOnSave": false,
"compilerOptions": {
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../dist/out-tsc-e2e",
"sourceMap": true,
"target": "es5",
"typeRoots": [
"../node_modules/@types"
]
}
}
const electron = require('electron')
const dotenv = require('dotenv')
// const edge = require('electron-edge')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow
const path = require('path')
const url = require('url')
// Require dotenv
dotenv.config();
if (process.env.DEBUG === 'true'){
// Require electron-reload for dev options
require('electron-reload')(__dirname);
}
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow = null;
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({width: 1000, height: 600, frame: true, minWidth: 1000, minHeight: 600, icon: "./src/assets/images/stratis-tray.png"})
if (process.env.DEBUG === 'false'){
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}));
} else {
mainWindow.loadURL('http://localhost:4200');
// Open the DevTools.
mainWindow.webContents.openDevTools();
}
// mainWindow.loadURL(url.format({
// pathname: path.join(__dirname, 'index.html'),
// protocol: 'file:',
// slashes: true
// }));
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', function () {
startServer()
createWindow()
createTray()
})
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
function startServer() {
// var startServer = edge.func('./assets/dll/Wallet.WebApi.dll');
}
function createTray() {
//Put the app in system tray
const Menu = electron.Menu
const Tray = electron.Tray
let appIcon = null
const iconName = process.platform === 'win32' ? './src/assets/images/stratis-tray.png' : './src/assets/images/stratis-tray.png'
const iconPath = path.join(__dirname, iconName)
appIcon = new Tray(iconPath)
const contextMenu = Menu.buildFromTemplate([{
label: 'Hide/Show',
click: function () {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
}
}])
appIcon.setToolTip('Breeze Wallet')
appIcon.setContextMenu(contextMenu)
app.on('window-all-closed', function () {
if (appIcon) appIcon.destroy()
})
}
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', 'angular-cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-remap-istanbul'),
require('angular-cli/plugins/karma')
],
files: [
{ pattern: './src/test.ts', watched: false }
],
preprocessors: {
'./src/test.ts': ['angular-cli']
},
mime: {
'text/x-typescript': ['ts','tsx']
},
remapIstanbulReporter: {
reports: {
html: 'coverage',
lcovonly: './coverage/coverage.lcov'
}
},
angularCli: {
config: './angular-cli.json',
environment: 'dev'
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['progress', 'karma-remap-istanbul']
: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
{
"name": "breeze-ui",
"version": "0.1.0",
"description": "Graphical User Interface for the Breeze Wallet.",
"main": "electron.js",
"license": "MIT",
"angular-cli": {},
"scripts": {
"ng": "ng",
"start": "ng serve --prod",
"test": "ng test",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "protractor",
"build": "ng build --prod",
"electron": "electron .",
"electron:build": "npm run electron:prepare && npm run electron:pack-win",
"electron:prepare": "npm run build && xcopy package.json dist && xcopy electron.js dist",
"electron:package": "npm run electron:prepare && npm run electron:pack-mac && npm run electron:pack-win && npm run electron:pack-linux",
"electron:pack-mac": "electron-packager dist --asar --overwrite --platform=darwin --arch=x64 --out=build",
"electron:pack-win": "electron-packager dist --asar --overwrite --platform=win32 --arch=ia32 --out=build",
"electron:pack-linux": "electron-packager dist --asar --overwrite --platform=linux --arch=x64 --out=build"
},
"private": true,
"dependencies": {
"@angular/animations": "^4.0.0",
"@angular/common": "^4.0.0",
"@angular/compiler": "^4.0.0",
"@angular/compiler-cli": "^4.0.0",
"@angular/core": "^4.0.0",
"@angular/forms": "^4.0.0",
"@angular/http": "^4.0.0",
"@angular/platform-browser": "^4.0.0",
"@angular/platform-browser-dynamic": "^4.0.0",
"@angular/platform-server": "^4.0.0",
"@angular/router": "^4.0.0",
"bootstrap": "^4.0.0-alpha.6",
"core-js": "^2.4.1",
"dotenv": "^4.0.0",
"electron-edge": "^6.5.4",
"rxjs": "^5.2.0",
"ts-helpers": "^1.1.2",
"typescript": "^2.2.2",
"zone.js": "^0.8.5"
},
"devDependencies": {
"@angular/cli": "^1.0.0",
"@angular/compiler-cli": "^4.0.0",
"@types/jasmine": "2.5.46",
"@types/node": "~7.0.12",
"codelyzer": "~2.0.0",
"dotenv": "^4.0.0",
"electron": "^1.6.2",
"electron-reload": "^1.1.0",
"jasmine-core": "~2.5.2",
"jasmine-spec-reporter": "~3.2.0",
"karma": "~1.5.0",
"karma-chrome-launcher": "~2.0.0",
"karma-cli": "~1.0.1",
"karma-coverage-istanbul-reporter": "^1.0.0",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.1",
"ts-node": "~3.0.2",
"tslint": "~4.5.1"
}
}
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
/*global jasmine */
var SpecReporter = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
useAllAngular2AppRoots: true,
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e'
});
},
onPrepare: function() {
jasmine.getEnv().addReporter(new SpecReporter());
}
};
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
<router-outlet></router-outlet>
\ No newline at end of file
/* tslint:disable:no-unused-variable */
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
});
TestBed.compileComponents();
});
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app works!'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app works!');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('app works!');
}));
});
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
constructor(private router: Router) {}
private isConfigured: boolean = true;
private checkConfigured(){
if (this.isConfigured) {
this.router.navigateByUrl('/wallet')
} else {
this.router.navigateByUrl('/setup')
}
}
ngOnInit() {
this.checkConfigured();
}
}
\ No newline at end of file
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { SetupModule } from './setup/setup.module';
import { WalletModule } from './wallet/wallet.module';
import { SharedModule } from './shared/shared.module';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppRoutingModule,
BrowserModule,
HttpModule,
SetupModule,
WalletModule,
SharedModule.forRoot()
],
declarations: [
AppComponent
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
\ No newline at end of file
import { Observable } from 'rxjs/Observable';
import { Component, OnInit } from '@angular/core';
import { ApiService } from '../../shared/api/api.service';
@Component({
selector: 'is-connected',
template: 'Wallet connected to API: {{result}}',
})
export class ApiComponent implements OnInit {
result: string;
constructor(private apiService: ApiService) {}
ngOnInit() {
this.apiService
.isConnected()
.subscribe((data: string) => this.result = data,
() => console.log("isConnected() complete from init"));
if (!this.result) {
this.result = "false"
}
}
}
<div class="content-wrapper">
<h1>
Please create a new wallet.
</h1>
<div>
<is-connected></is-connected>
</div>
<div class="form-group">
<label for="name">Name:</label>
<input class="form-control" type="text" #walletName required>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input class="form-control" type="password" #walletPassword required>
</div>
<div class="form-group">
<label for="networklabel">Network:</label>
<select name="network" #walletNetwork>
<option value="main">Main</option>
<option value="test">Testnet</option>
</select>
</div>
<div class="form-group">
<label for="path">Path:</label>
<input class="form-control" type="text" #walletPath required>
</div>
<button type="submit" (click)="createWallet(walletPassword.value, walletNetwork.value, walletPath.value, walletName.value)">Create</button>
<div>
<label>Mnemonic:</label>
</div>
<div>
<label>{{body}}</label>
</div>
</div>
\ No newline at end of file
import { Component, Injectable } from '@angular/core';
import { ApiService } from '../../shared/api/api.service';
import { SafeCreation } from '../../shared/safe-creation';
import { Mnemonic } from '../../shared/mnemonic';
@Component({
selector: 'create-component',
templateUrl: './create.component.html',
styleUrls: ['./create.component.css'],
})
export class CreateComponent {
constructor(private apiService: ApiService) {}
private newWallet: SafeCreation;
private body: string;
private createWallet(password: string, network: string, folderPath: string, name: string, ) {
this.newWallet.password = password;
this.newWallet.network = network;
this.newWallet.folderPath = folderPath;
this.newWallet.name = name;
this.apiService
.createWallet(this.newWallet)
//.map(res => {let body = res.text()})
.subscribe((response: string) => this.body = response,
() => console.log("createWallet() complete from init"));
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SetupComponent } from './setup.component';
const routes: Routes = [
{ path: 'setup', component: SetupComponent }
];
@NgModule({
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class SetupRoutingModule {}
<h1>Welcome to setup</h1>
<create-component></create-component>
\ No newline at end of file
import { Component } from '@angular/core';
@Component({
selector: 'setup-component',
templateUrl: './setup.component.html',
styleUrls: ['./setup.component.css'],
})
export class SetupComponent {
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';
import { SetupComponent } from './setup.component';
import { CreateComponent } from './create/create.component';
import { ApiComponent } from './create/api.component';
import { SharedModule } from '../shared/shared.module';
import { SetupRoutingModule } from './setup-routing.module';
import { ApiService } from '../shared/api/api.service';
@NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
SetupRoutingModule,
SharedModule
],
declarations: [
CreateComponent,
SetupComponent,
ApiComponent
],
exports: [SetupComponent],
providers: []
})
export class SetupModule { }
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import { SafeCreation } from '../safe-creation';
import { Mnemonic } from '../mnemonic';
@Injectable()
export class ApiService {
constructor(private http: Http) {};
private webApiUrl = 'http://localhost:5000/';
private headers = new Headers({'Content-Type': 'application/json'});
isConnected(): Observable<string> {
return this.http
.get(this.webApiUrl + 'api/safe/connected')
.map(data => data.json())
}
createWallet(data: SafeCreation): Observable<any> {
console.log(JSON.stringify(data));
return this.http
.post(this.webApiUrl + 'api/safe', JSON.stringify(data), {headers: this.headers})
.map(response => response.json());
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
}
export class Mnemonic {
mnemonic: string;
}
export class SafeCreation {
password: string;
network: string;
folderPath: string;
name: string;
}
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { ApiService} from './api/api.service';
@NgModule({
imports: [CommonModule, RouterModule],
declarations: [],
exports: [CommonModule, FormsModule, RouterModule]
})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: SharedModule,
providers: [ApiService]
};
}
}
\ No newline at end of file
import { Component } from '@angular/core';
@Component({
selector: 'history-component',
templateUrl: './history.component.html',
styleUrls: ['./history.component.css'],
})
export class HistoryComponent {
}
<nav class="navbar navbar-fixed-top">
<div class="container">
<a class="navbar-brand">Breeze</a>
<ul class="nav navbar-nav" routerLinkActive="active">
<li class="nav-item"><a class="nav-link" routerLink="send">Send</a></li>
<li class="nav-item"><a class="nav-link" routerLink="receive">Receive</a></li>
<li class="nav-item"><a class="nav-link" routerLink="history">History</a></li>
</ul>
</div>
</nav>
import { Component } from '@angular/core';
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css'],
})
export class MenuComponent {
}
<div class="content-wrapper">
<h1>Receive</h1>
<div>
<label>Unused Receive Addresses</label>
<div>
</div>
</div>
<div>
<label>Used Receive Addresses</label>
</div>
<div>
<label>Change Addresses</label>
</div>
</div>
\ No newline at end of file
import { Component } from '@angular/core';
@Component({
selector: 'receive-component',
templateUrl: './receive.component.html',
styleUrls: ['./receive.component.css'],
})
export class ReceiveComponent {
}
\ No newline at end of file
<div class="content-wrapper">
<h1>Send</h1>
<form (ngSubmit)="onSubmit()" #sendForm="ngForm">
<div class="form-group">
<label for="toAddress">Pay To: </label>
<input type="text" class="form-control" id="name" required name="toAddress">
</div>
<div class="form-group">
<label for="amount">Amount</label>
<input type="text" class="form-control" id="amount" required name="amount">
</div>
<button type="submit" class="btn btn-success">Submit</button>
</form>
</div>
\ No newline at end of file
import { Component } from '@angular/core';
import { ApiService } from '../../shared/api/api.service';
@Component({
selector: 'send-component',
templateUrl: './send.component.html',
styleUrls: ['./send.component.css'],
})
export class SendComponent {
constructor(private apiService: ApiService) {}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { WalletComponent } from './wallet.component';
import { SendComponent } from './send/send.component';
import { ReceiveComponent } from './receive/receive.component';
import { HistoryComponent } from './history/history.component';
const routes: Routes = [
{ path: 'wallet', component: WalletComponent,
children: [
{ path: '', redirectTo:'send', pathMatch:'full' },
{ path: 'send', component: SendComponent},
{ path: 'receive', component: ReceiveComponent},
{ path: 'history', component: HistoryComponent}
]
},
];
@NgModule({
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class WalletRoutingModule {}
#sidepanel {
margin: 0;
padding: 0;
height: 100%;
width: 200px;
position: fixed;
overflow: auto;
}
#content {
margin-left: 200px;
}
\ No newline at end of file
<div id="container">
<div id="sidepanel">
<app-menu></app-menu>
</div>
<div id="content">
<router-outlet></router-outlet>
</div>
</div>
\ No newline at end of file
import { Component } from '@angular/core';
@Component({
selector: 'wallet-component',
templateUrl: './wallet.component.html',
styleUrls: ['./wallet.component.css'],
})
export class WalletComponent {
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';
import { WalletComponent } from './wallet.component';
import { MenuComponent } from './menu/menu.component';
import { SendComponent } from './send/send.component';
import { ReceiveComponent } from './receive/receive.component';
import { HistoryComponent } from './history/history.component';
import { SharedModule } from '../shared/shared.module';
import { WalletRoutingModule } from './wallet-routing.module';
@NgModule({
imports: [
BrowserModule,
FormsModule,
HttpModule,
WalletRoutingModule,
SharedModule
],
declarations: [
WalletComponent,
MenuComponent,
ReceiveComponent,
SendComponent,
HistoryComponent,
],
exports: [
WalletComponent
]
})
export class WalletModule { }
export const environment = {
production: true
};
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `angular-cli.json`.
export const environment = {
production: false
};
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>BreezeUI</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { AppModule } from './app/app.module';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule);
// This file includes polyfills needed by Angular and is loaded before the app.
// You can add your own extra polyfills to this file.
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/set';
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
// If you need to support the browsers/features below, uncomment the import
// and run `npm install import-name-here';
// Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
// Needed for: IE9
// import 'classlist.js';
// Animations
// Needed for: All but Chrome and Firefox, Not supported in IE9
// import 'web-animations-js';
// Date, currency, decimal and percent pipes
// Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
// import 'intl';
// NgClass on SVG elements
// Needed for: IE10, IE11
// import 'classlist.js';
/* You can add global styles to this file, and also import other style files */
.content-wrapper {
width: 100%;
height: 100%;
}
\ No newline at end of file
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/long-stack-trace-zone';
import 'zone.js/dist/proxy.js';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/jasmine-patch';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare var __karma__: any;
declare var require: any;
// Prevent Karma from running prematurely.
__karma__.loaded = function () {};
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
// Finally, start Karma to run the tests.
__karma__.start();
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": [ "es2015", "dom" ],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
"exclude": [
"node_modules",
"dist"
]
}
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"import-blacklist": [true, "rxjs"],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
"static-before-instance",
"variables-before-functions"
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [true, "attribute", "app", "camelCase"],
"component-selector": [true, "element", "app", "kebab-case"],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"no-access-missing-member": true,
"templates-use-public": true,
"invoke-injectable": true
}
}
...@@ -6,28 +6,26 @@ using System.Security; ...@@ -6,28 +6,26 @@ using System.Security;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Breeze.Wallet.Models; using Breeze.Wallet.Models;
using Breeze.Wallet.Wrappers; using Breeze.Wallet.Wrappers;
using Stratis.Bitcoin;
namespace Breeze.Wallet.Controllers namespace Breeze.Wallet.Controllers
{ {
[Route("api/[controller]")] [Route("api/v{version:apiVersion}/[controller]")]
public class SafeController : Controller public class WalletController : Controller
{ {
private readonly ISafeWrapper safeWrapper; private readonly IWalletWrapper walletWrapper;
public SafeController(ISafeWrapper safeWrapper) public WalletController(IWalletWrapper walletWrapper)
{ {
this.safeWrapper = safeWrapper; this.walletWrapper = walletWrapper;
} }
/// <summary> /// <summary>
/// Creates a new safe on the local machine. /// Creates a new wallet on the local machine.
/// </summary> /// </summary>
/// <param name="safeCreation">The object containing the parameters used to create the wallet.</param> /// <param name="walletCreation">The object containing the parameters used to create the wallet.</param>
/// <returns>A JSON object contaibibg the mnemonic created for the new wallet.</returns> /// <returns>A JSON object containing the mnemonic created for the new wallet.</returns>
[HttpPost] [HttpPost]
public IActionResult Create([FromBody]SafeCreationModel safeCreation) public IActionResult Create([FromBody]WalletCreationModel walletCreation)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
...@@ -38,7 +36,7 @@ namespace Breeze.Wallet.Controllers ...@@ -38,7 +36,7 @@ namespace Breeze.Wallet.Controllers
try try
{ {
var mnemonic = this.safeWrapper.Create(safeCreation.Password, safeCreation.FolderPath, safeCreation.Name, safeCreation.Network); var mnemonic = this.walletWrapper.Create(walletCreation.Password, walletCreation.FolderPath, walletCreation.Name, walletCreation.Network);
return this.Json(mnemonic); return this.Json(mnemonic);
} }
catch (NotSupportedException e) catch (NotSupportedException e)
...@@ -50,7 +48,8 @@ namespace Breeze.Wallet.Controllers ...@@ -50,7 +48,8 @@ namespace Breeze.Wallet.Controllers
} }
} }
public IActionResult Load(SafeLoadModel safeLoad) [HttpGet]
public IActionResult Load([FromQuery]WalletLoadModel walletLoad)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
...@@ -61,8 +60,8 @@ namespace Breeze.Wallet.Controllers ...@@ -61,8 +60,8 @@ namespace Breeze.Wallet.Controllers
try try
{ {
var safe = this.safeWrapper.Load(safeLoad.Password, safeLoad.FolderPath, safeLoad.Name); var wallet = this.walletWrapper.Load(walletLoad.Password, walletLoad.FolderPath, walletLoad.Name);
return this.Json(safe); return this.Json(wallet);
} }
catch (FileNotFoundException e) catch (FileNotFoundException e)
...@@ -88,7 +87,7 @@ namespace Breeze.Wallet.Controllers ...@@ -88,7 +87,7 @@ namespace Breeze.Wallet.Controllers
[Route("recover")] [Route("recover")]
[HttpPost] [HttpPost]
public IActionResult Recover([FromBody]SafeRecoveryModel safeRecovery) public IActionResult Recover([FromBody]WalletRecoveryModel walletRecovery)
{ {
// checks the request is valid // checks the request is valid
if (!this.ModelState.IsValid) if (!this.ModelState.IsValid)
...@@ -99,8 +98,8 @@ namespace Breeze.Wallet.Controllers ...@@ -99,8 +98,8 @@ namespace Breeze.Wallet.Controllers
try try
{ {
var safe = this.safeWrapper.Recover(safeRecovery.Password, safeRecovery.FolderPath, safeRecovery.Name, safeRecovery.Network, safeRecovery.Mnemonic); var wallet = this.walletWrapper.Recover(walletRecovery.Password, walletRecovery.FolderPath, walletRecovery.Name, walletRecovery.Network, walletRecovery.Mnemonic);
return this.Json(safe); return this.Json(wallet);
} }
catch (FileNotFoundException e) catch (FileNotFoundException e)
......
...@@ -7,21 +7,21 @@ namespace Breeze.Wallet.Models ...@@ -7,21 +7,21 @@ namespace Breeze.Wallet.Models
/// <summary> /// <summary>
/// Object used to create a new wallet /// Object used to create a new wallet
/// </summary> /// </summary>
public class SafeCreationModel public class WalletCreationModel
{ {
[Required(ErrorMessage = "A password is required.")] [Required(ErrorMessage = "A password is required.")]
public string Password { get; set; } public string Password { get; set; }
public string Network { get; set; } public string Network { get; set; }
[Required(ErrorMessage = "The folder path where the safe will be created is required.")] [Required(ErrorMessage = "The folder path where the wallet will be created is required.")]
public string FolderPath { get; set; } public string FolderPath { get; set; }
[Required(ErrorMessage = "The name of the safe to create is missing.")] [Required(ErrorMessage = "The name of the wallet to create is missing.")]
public string Name { get; set; } public string Name { get; set; }
} }
public class SafeLoadModel public class WalletLoadModel
{ {
[Required(ErrorMessage = "A password is required.")] [Required(ErrorMessage = "A password is required.")]
public string Password { get; set; } public string Password { get; set; }
...@@ -29,11 +29,11 @@ namespace Breeze.Wallet.Models ...@@ -29,11 +29,11 @@ namespace Breeze.Wallet.Models
[Required(ErrorMessage = "The folder path is required.")] [Required(ErrorMessage = "The folder path is required.")]
public string FolderPath { get; set; } public string FolderPath { get; set; }
[Required(ErrorMessage = "The name of the safe is missing.")] [Required(ErrorMessage = "The name of the wallet is missing.")]
public string Name { get; set; } public string Name { get; set; }
} }
public class SafeRecoveryModel public class WalletRecoveryModel
{ {
[Required(ErrorMessage = "A mnemonic is required.")] [Required(ErrorMessage = "A mnemonic is required.")]
public string Mnemonic { get; set; } public string Mnemonic { get; set; }
...@@ -44,7 +44,7 @@ namespace Breeze.Wallet.Models ...@@ -44,7 +44,7 @@ namespace Breeze.Wallet.Models
[Required(ErrorMessage = "The folder path is required.")] [Required(ErrorMessage = "The folder path is required.")]
public string FolderPath { get; set; } public string FolderPath { get; set; }
[Required(ErrorMessage = "The name of the safe is missing.")] [Required(ErrorMessage = "The name of the wallet is missing.")]
public string Name { get; set; } public string Name { get; set; }
public string Network { get; set; } public string Network { get; set; }
......
...@@ -23,9 +23,9 @@ namespace Breeze.Wallet ...@@ -23,9 +23,9 @@ namespace Breeze.Wallet
.AddFeature<WalletFeature>() .AddFeature<WalletFeature>()
.FeatureServices(services => .FeatureServices(services =>
{ {
services.AddTransient<ISafeWrapper, SafeWrapper>(); services.AddTransient<IWalletWrapper, WalletWrapper>();
services.AddTransient<ITrackerWrapper, TrackerWrapper>(); services.AddTransient<ITrackerWrapper, TrackerWrapper>();
services.AddSingleton<SafeController>(); services.AddSingleton<WalletController>();
}); });
}); });
......
...@@ -5,7 +5,7 @@ using System.Threading.Tasks; ...@@ -5,7 +5,7 @@ using System.Threading.Tasks;
namespace Breeze.Wallet namespace Breeze.Wallet
{ {
public class SafeModel public class WalletModel
{ {
public string Network { get; set; } public string Network { get; set; }
......
...@@ -4,12 +4,12 @@ namespace Breeze.Wallet.Wrappers ...@@ -4,12 +4,12 @@ namespace Breeze.Wallet.Wrappers
/// <summary> /// <summary>
/// An interface enabling wallet operations. /// An interface enabling wallet operations.
/// </summary> /// </summary>
public interface ISafeWrapper public interface IWalletWrapper
{ {
string Create(string password, string folderPath, string name, string network); string Create(string password, string folderPath, string name, string network);
SafeModel Load(string password, string folderPath, string name); WalletModel Load(string password, string folderPath, string name);
SafeModel Recover(string password, string folderPath, string name, string network, string mnemonic); WalletModel Recover(string password, string folderPath, string name, string network, string mnemonic);
} }
} }
...@@ -6,64 +6,64 @@ using NBitcoin; ...@@ -6,64 +6,64 @@ using NBitcoin;
namespace Breeze.Wallet.Wrappers namespace Breeze.Wallet.Wrappers
{ {
/// <summary> /// <summary>
/// An implementation of the <see cref="ISafeWrapper"/> interface. /// An implementation of the <see cref="IWalletWrapper"/> interface.
/// </summary> /// </summary>
public class SafeWrapper : ISafeWrapper public class WalletWrapper : IWalletWrapper
{ {
/// <summary> /// <summary>
/// Creates a safe on the local device. /// Creates a wallet on the local device.
/// </summary> /// </summary>
/// <param name="password">The user's password.</param> /// <param name="password">The user's password.</param>
/// <param name="folderPath">The folder where the safe will be saved.</param> /// <param name="folderPath">The folder where the wallet will be saved.</param>
/// <param name="name">The name of the safe.</param> /// <param name="name">The name of the wallet.</param>
/// <param name="network">The network for which to create a safe.</param> /// <param name="network">The network for which to create a wallet.</param>
/// <returns>A mnemonic allowing recovery of the safe.</returns> /// <returns>A mnemonic allowing recovery of the wallet.</returns>
public string Create(string password, string folderPath, string name, string network) public string Create(string password, string folderPath, string name, string network)
{ {
Mnemonic mnemonic; Mnemonic mnemonic;
Safe safe = Safe.Create(out mnemonic, password, Path.Combine(folderPath, $"{name}.json"), this.GetNetwork(network)); Safe wallet = Safe.Create(out mnemonic, password, Path.Combine(folderPath, $"{name}.json"), this.GetNetwork(network));
return mnemonic.ToString(); return mnemonic.ToString();
} }
/// <summary> /// <summary>
/// Loads a safe from the local device. /// Loads a wallet from the local device.
/// </summary> /// </summary>
/// <param name="password">The user's password.</param> /// <param name="password">The user's password.</param>
/// <param name="folderPath">The folder where the safe will be loaded.</param> /// <param name="folderPath">The folder where the wallet will be loaded.</param>
/// <param name="name">The name of the safe.</param> /// <param name="name">The name of the wallet.</param>
/// <returns>The safe loaded from the local device</returns> /// <returns>The wallet loaded from the local device</returns>
public SafeModel Load(string password, string folderPath, string name) public WalletModel Load(string password, string folderPath, string name)
{ {
Safe safe = Safe.Load(password, Path.Combine(folderPath, $"{name}.json")); Safe wallet = Safe.Load(password, Path.Combine(folderPath, $"{name}.json"));
//TODO review here which data should be returned //TODO review here which data should be returned
return new SafeModel return new WalletModel
{ {
Network = safe.Network.Name, Network = wallet.Network.Name,
Addresses = safe.GetFirstNAddresses(10).Select(a => a.ToWif()), Addresses = wallet.GetFirstNAddresses(10).Select(a => a.ToWif()),
FileName = safe.WalletFilePath FileName = wallet.WalletFilePath
}; };
} }
/// <summary> /// <summary>
/// Recovers a safe from the local device. /// Recovers a wallet from the local device.
/// </summary> /// </summary>
/// <param name="password">The user's password.</param> /// <param name="password">The user's password.</param>
/// <param name="folderPath">The folder where the safe will be loaded.</param> /// <param name="folderPath">The folder where the wallet will be loaded.</param>
/// <param name="name">The name of the safe.</param> /// <param name="name">The name of the wallet.</param>
/// <param name="network">The network in which to creae this wallet</param> /// <param name="network">The network in which to creae this wallet</param>
/// <param name="mnemonic">The user's mnemonic for the safe.</param> /// <param name="mnemonic">The user's mnemonic for the wallet.</param>
/// <returns></returns> /// <returns></returns>
public SafeModel Recover(string password, string folderPath, string name, string network, string mnemonic) public WalletModel Recover(string password, string folderPath, string name, string network, string mnemonic)
{ {
Safe safe = Safe.Recover(new Mnemonic(mnemonic), password, Path.Combine(folderPath, $"{name}.json"), this.GetNetwork(network)); Safe wallet = Safe.Recover(new Mnemonic(mnemonic), password, Path.Combine(folderPath, $"{name}.json"), this.GetNetwork(network));
//TODO review here which data should be returned //TODO review here which data should be returned
return new SafeModel return new WalletModel
{ {
Network = safe.Network.Name, Network = wallet.Network.Name,
Addresses = safe.GetFirstNAddresses(10).Select(a => a.ToWif()), Addresses = wallet.GetFirstNAddresses(10).Select(a => a.ToWif()),
FileName = safe.WalletFilePath FileName = wallet.WalletFilePath
}; };
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
"dependencies": { "dependencies": {
"HBitcoin": "0.1.5", "HBitcoin": "0.1.5",
"Microsoft.AspNetCore.Mvc.Versioning": "1.0.3",
"NBitcoin": "3.0.2.10", "NBitcoin": "3.0.2.10",
"NETStandard.Library": "1.6.1", "NETStandard.Library": "1.6.1",
"Stratis.Bitcoin": "1.0.1.2-alpha" "Stratis.Bitcoin": "1.0.1.2-alpha"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment