pax_global_header 0000666 0000000 0000000 00000000064 13334556736 0014531 g ustar 00root root 0000000 0000000 52 comment=91aec236e1ca8ec0e2b7702ed41121ad2fd7436f
Breeze-1.0.0/ 0000775 0000000 0000000 00000000000 13334556736 0012743 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/.gitignore 0000664 0000000 0000000 00000011170 13334556736 0014733 0 ustar 00root root 0000000 0000000 ## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# UI ignores
# compiled output
**/app-builds
**/assets/daemon
**/dist
**/tmp
**/build
# dependencies
**/node_modules
package-lock.json
# 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
################################################################################
# This .gitignore file was automatically created by Microsoft(R) Visual Studio.
################################################################################
*.user
# DNX
project.lock.json
/Breeze/src/Breeze.Daemon/Wallets
/Breeze/src/Breeze.Daemon/Logs
/Breeze.UI/.vscode/.BROWSE.VC.DB-wal
/Breeze.UI/.vscode/.BROWSE.VC.DB-shm
/Breeze.UI/daemon
/Breeze.UI/app-builds
/Breeze.UI/dist
Breeze-1.0.0/.gitmodules 0000664 0000000 0000000 00000000205 13334556736 0015115 0 ustar 00root root 0000000 0000000 [submodule "StratisBitcoinFullNode"]
path = StratisBitcoinFullNode
url = https://github.com/stratisproject/StratisBitcoinFullNode/
Breeze-1.0.0/.travis.yml 0000664 0000000 0000000 00000002616 13334556736 0015061 0 ustar 00root root 0000000 0000000 language: csharp
mono: none
dotnet: 2.1.301
matrix:
include:
- os: linux # Ubuntu 14.04
dist: trusty
sudo: required
- os: osx # OSX 10.12
osx_image: xcode9
before_install:
- brew update
- ulimit -n 4098
- os_platform=darwin
# branches to build
branches:
only:
- master
env:
global:
- log_prefix=[$TRAVIS_OS_NAME]
- arch=x64
- configuration=Release
- os_platform=linux
- CSC_IDENTITY_AUTO_DISCOVERY=false
cache:
directories:
- ${TRAVIS_BUILD_DIR}/Breeze.UI/node_modules
- $HOME/.electron
- $HOME/.nuget/packages
- /usr/share/dotnet/sdk/ # dotnet path for linux
- /Users/travis/.dotnet/sdk/ # dotnet path for mac
# Work around NuGet issue #2163
# https://github.com/NuGet/Home/issues/2163
# https://github.com/travis-ci/travis-ci/issues/7728
install:
- nvm install 8.11.2
- npm install -g npm@6.2.0
before_script:
- if [ -z "$TRAVIS_TAG" ] ; then TRAVIS_TAG=cd-unstable; fi
- npm --version
- nvm --version
script:
- chmod +x build.sh
- "./build.sh"
deploy:
provider: releases
api_key:
secure: $secure_github_key # this key is set on the Travis build page
file_glob: true
file:
- "$TRAVIS_BUILD_DIR/Breeze.UI/app-builds/*.deb"
- "$TRAVIS_BUILD_DIR/Breeze.UI/app-builds/*.tar.gz"
- "$TRAVIS_BUILD_DIR/Breeze.UI/app-builds/*.dmg"
skip_cleanup: true
overwrite: true
prerelease: true
on:
branch: master
tags: true Breeze-1.0.0/Breeze.Documentation/ 0000775 0000000 0000000 00000000000 13334556736 0016767 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.Documentation/API contribution guidelines.md 0000664 0000000 0000000 00000001770 13334556736 0024540 0 ustar 00root root 0000000 0000000 Contributing to the Stratis Breeze API
================================
The Stratis team maintains a few guidelines, which are provided below. Many of these are straightforward.
For any questions a Stratis team member will be happy to explain more.
We follow the Stratis Full node's [contributing](https://github.com/stratisproject/StratisBitcoinFullNode/blob/master/Documentation/contributing.md), [coding style](https://github.com/stratisproject/StratisBitcoinFullNode/blob/master/Documentation/coding-style.md) and [testing](https://github.com/stratisproject/StratisBitcoinFullNode/blob/master/Documentation/testing-guidelines.md) guidelines.
By contributing to this repository, you agree to license your work under the
[Stratis](https://github.com/stratisproject/StratisBitcoinFullNode/blob/master/LICENSE) license unless specified otherwise at
the top of the file itself. Any work contributed where you are not the original
author must contain its license header with the original author(s) and source.
Breeze-1.0.0/Breeze.Documentation/ApiSpecification.md 0000664 0000000 0000000 00000031027 13334556736 0022526 0 ustar 00root root 0000000 0000000 `/api/`
## Request/Response
RESPONSE: response code (`200` for all successful requests, `4xx`/`5xx` if error, see later)
HEADERS: `Content-Type:application/json`
## Errors
### General errors
BODY
The error response is an array of error objects.
Depending on the circumstance the API will either return an error at the first encounter or will continue until multiple errors are gathered.
```
{
"errors": [
{
"status": 400,
"message": "No wallet file found at Wallets\\testwallet.json",
"description": "System.ArgumentException: No wallet file found at..."
}
]
}
```
### wallet is not created
This error message comes at all request if the wallet is not created yet, except
- `POST /wallet/create`
- `POST /wallet/recover`
- `POST /wallet/send-transaction`
```
404 (Not Found) - "wallet is not created"
```
### wallet is not decrypted
This error message comes at all request if the wallet is not loaded yet, except
- `POST /wallet/create`
- `POST /wallet/recover`
- `POST /wallet/send-transaction`
- `POST /wallet/load`
- `DELETE /wallet`
```
400 (Bad Request) - "wallet is not decrypted"
```
## Key Management
```
GET /wallet/general-info - Displays general information on the wallet
GET /wallet/extpubkey - Displays the extpubkey of the specified account
GET /wallet/status - Displays dynamic information on the wallet
POST /wallet/create - Creates the wallet
POST /wallet/load - Loads the wallet and starts syncing
POST /wallet/recover - Recovers the wallet
DELETE /wallet - Deletes the wallet
POST /wallet/account
POST /wallet/address
```
## Syncing
```
GET /wallet/mempool/?allow=[true/false] - Allows or disallows mempool syncing
```
## Key Monitoring
```
GET /wallet/receive/[account1/account2] - Displays unused receive addresses of the specified wallet account
GET /wallet/history/[account1/account2] - Displays the history of the specified wallet account
GET /wallet/balance/[account1/account2] - Displays the balances of the specified wallet account
```
## Transaction building and sending
```
POST /wallet/build-transaction/[account1/account2] - Attempts to build a transaction with the specified wallet account
POST /wallet/send-transaction - Attempts to send a transaction
```
# Details
## GET /wallet/mnemonic - Generate a mnemonic
### Query parameters
`language` (optional) - the language for the words in the mnemonic. Options are: English, French, Spanish, Japanese, ChineseSimplified and ChineseTraditional. The default is 'English'.
`wordcount` (optional) - the number of words in the mnemonic. Options are: 12,15,18,21 or 24. the default is 12.
### Examples
request
```
http://localhost:37220/api/wallet/mnemonic?wordcount=15&language=French
```
response
```
"larme essorer sabre casque gentil flamme érosion acheter caribou broder endiguer ordonner vacarme dosage défrayer"
```
request
```
http://localhost:37220/api/wallet/mnemonic?wordcount=12&language=english
```
response
```
"gravity sock glove cage divert creek mountain connect small banana depend thunder"
```
## GET /wallet/general-info - Displays general information on the wallet
### Query parameters
`name` (required) - the name of the wallet.
### Examples
#### Request
```
http://localhost:37220/api/wallet/general-info?name=testwallet
```
#### Response
```
{
"walletFilePath":null,
"network":"testnet", //"main", "testnet", "stratismain", "stratistest"
"creationTime":"1511169493",
"isDecrypted":true,
"lastBlockSyncedHeight":1231116,
"chainTip":1231116,
"isChainSynced":true,
"connectedNodes":8
}
```
## GET /wallet/extpubkey - Displays the extpubkey of the specified account
### Query parameters
`walletName` (required) - the name of the wallet.
### Examples
#### Request
```
http://localhost:37220/api/wallet/extpubkey?walletName=testwallet&accountName=account%200
```
#### Response
Returns the public key hash of the account.
```
"tpubDDVB7J4oNpyWFUVp91UcQnxUVJExWPV5NecBFTzQVH6d3A9pcrYCvu8jGzCHVAzyD99Sk3g3kLYMx6MocpzmtusmDgpbx27Msc5iCKefMUm"
```
## GET /wallet/status - Displays dynamic information on the wallet
### Responses
```
{
"connectedNodeCount": "7",
"maxConnextedNodeCount": "8",
"headerChainHeight": "1048",
"trackingHeight": "1047",
"trackedTransactionCount": "306",
"trackedScriptPubKeyCount": "100",
"walletState": "syncingBlocks", // notStarted/syncingHeaders/syncingBlocks/mempoolStalling/syncingMempool/synced
"historyChangeBump": "231321" // every time something changes this number is dumped. So it's enough to poll this get request and no need to poll the history or balances get request constantly to update the up, but only when this number changes
}
```
## POST /wallet/create - Creates the wallet
### Parameters
`name` - case-sensitive name of the wallet to be created.
`password` - password for the wallet to be created.
`mnemonic` (optional) - the user's mnemonic for the wallet.
```
{
"name": "testwallet",
"password": "testpassword",
"mnemonic": "gravity sock glove cage divert creek mountain connect small banana depend thunder"
}
```
### Responses
Returns the mnemonic for the wallet. If there was no mnemonic defined as input then a newly generated word list will be returned.
```
{
"mnemonic": "gravity sock glove cage divert creek mountain connect small banana depend thunder",
}
```
## POST /wallet/load - Loads the wallet and starts syncing
### Parameters
```
{
"folderPath": "Wallets", // optional, if the folder path is not the default one
"name": "testwallet",
"password": "testpassword"
}
```
### Response
```
200 (OK)
```
## POST /wallet/recover - Recovers the wallet
### Parameters
```
{
"network": "testnet", // "main" or "testnet"
"folderPath": "Wallets", // optional, if the folder path is not the default one
"name": "testwallet-recovered",
"password": "testpassword",
"mnemonic": "gravity sock glove cage divert creek mountain connect small banana depend thunder",
"creationTime": "2017-02-25 16:20:33" // date from which to start looking for transactions
}
```
### Response
Cannot check if the password is good or not. If the password is wrong it'll recover a wallet with the wrong password.
```
200 (OK)
```
## DELETE /wallet - Deletes the wallet
Works as expected.
## POST /wallet/account - Gets an unused account from the wallet
This endpoint will get the first account containing no transaction or will create a new account.
### Parameters
```
{
"walletName": "testwallet",
"password": "testpassword",
"coinType": 105 // 0 - Bitcoin, 105 - Stratis
}
```
### Responses
```
"account one"
```
## GET /wallet/address - Gets an unused address
This endpoint will get the last address containing no transaction or will create a new address.
### Query parameters
`walletName` (required) - the name of the wallet in which this address is contained.
`coinType` (required) - the type of coin for which to get the address, e.g 0 for bitcoin, 105 for stratis.
`accountName` (required) - the name of the account in which this address is contained.
### Responses
```
"1HDypWxXWZC5KXK259EHMnrWaa2youy7Mj"
```
## GET /wallet/receive/[account1/account2] - Displays unused receive addresses of the specified wallet account
### Responses
```
{
"addresses": // 7 unused receive address (7 is the best number: https://www.psychologytoday.com/blog/fulfillment-any-age/201109/7-reasons-we-7-reasons)
[
"mzz63n3n89KVeHQXRqJEVsQX8MZj5zeqCw",
"mhm1pFe2hH7yqkdQhwbBQ8qLnMZqfL6jXb",
"mmRzqMDBrfNxMfryQSYec3rfPHXURNapBA",
"my2ELDBqLGVz1ER7CMynDqG4BUpV2pwfR5",
"mmwccp4GefhPn4P6Mui6DGLGzHTVyQ12tD",
"miTedyDXJAz6GYMRasiJk9M3ibnGnb99M1",
"mrsb39MmPceSPfKAURTH23hYgLRH1M1Uhg"
]
}
```
## GET /wallet/history - Displays the history of the specified wallet account
### Query parameters
`walletName` (required) - the name of the wallet.
`coinType` (required) - the type of coin, e.g 0 for bitcoin, 105 for stratis.
### Responses
```
{
"transactionsHistory": [
{
"type": "send",
"id": "6358161c713688e372481fce7f20f3f8692ab2e4e657f3d9afa750ebee54e6c3",
"amount": 500000,
"payments": [
{
"destinationAddress": "mt7W2Zf69KC9472TPCzUeLLhBDSmC82AWz",
"amount": 500000
}
],
"fee": 100000,
"confirmedInBlock": 1122310,
"timestamp": "1494594937"
},
{
"type": "received",
"toAddress": "mnDsG7kTYCeVNqnEmfvdYeNgZwxhjqm2jc",
"id": "75ce74643aae01ccbe2bbc05efb4788cc9a16a9192add4d7082561a40a541057",
"amount": 110000000,
"confirmedInBlock": 1122292,
"timestamp": "1494591670"
}
]
}
```
## GET /wallet/balance - Displays the balances of the specified wallet account
### Query parameters
`walletName` (required) - the name of the wallet.
`coinType` (required) - the type of coin, e.g 0 for bitcoin, 105 for stratis.
### Examples
#### Request
```
http://localhost:37220/api/wallet/balance?walletName=testwallet
```
#### Response
```
{
"balances": [
{
"accountName": "account one",
"accountHdPath": "m/44'/0'/0'",
"coinType": 0,
"amountConfirmed": 209268016,
"amountUnconfirmed": 0
}
]
}
```
Confirmed balance is the (amount of unspent confirmed outputs - unconfirmed outgoing transactions). It cannot be negative.
Unconfirmed balance is the difference of unconfirmed incoming and outgoing transactions. It can be negative.
## POST /wallet/build-transaction/ - Attempts to build a transaction with the specified wallet account
### Parameters
```
{
"walletName": "testwallet",
"accountName": "account 0",
"coinType": 0,
"password": "password",
"destinationAddress": "1Xyz...",
"amount": "0.12", // in btc, if 0, then spends all available
"feeType": "low", // "low"/"medium"/"high"
"allowUnconfirmed": true // if spending unconfirmed outputs is allowed
}
```
### Responses
#### Successful
```
{
"fee": "0.0001",
"hex": "0100000002d9dced2b6fc80c706d3564670cb6706afe7a798863a9218efcdcf415d58f0f82000000006a473044022030b8bea478444bd52f08de33b082cde1176d3137111f506eefefa91b47b1f6bf02204f12746abd1aeac5805872d163592cf145967fa0619339a9c5348d674852ef4801210224ec1e4c270ce373e6999eebfa01d0a7e7db3c537c026f265233350d5aab81fbfeffffffa0706db65c5e3594d43df5a2a8b6dfd3c9ee506b678f8c26f7820b324b26aa0f000000006a473044022061b718034f876590d6d80bac77a63248b2548d934849acd02c4f4236309e853002201aded6b24f553b6902cf571276b37b12f76b75650164d8738c74469b4edd547e012103d649294a0ca4db920a69eacd6a75cb8a38ae1b81129900621ce45e6ba3438a7bfeffffff0280a90300000000001976a914d0965947ebb329b776328624ebde8f8b32dc639788ac1cc80f00000000001976a914c2a420d34fc86cff932b8c3191549a0ddfd2b0d088acba770f00",
"transactionId": "86f348bce07b04b2f7a00d882349e66d98765e935484516ce5fca97685566155"
}
```
#### Errors
```
400 - "wallet is not synced"
```
## POST /wallet/send-transaction - Attempts to send a transaction
### Parameters
```
{
"hex": "01000000061b1ca819e76f9131b23335ec905ffc5fc27e36a7843a5b7c6d1b455b904359f7000000006b483045022100c11f78ce7f02b2312b6675d3ad99cec6ede879d446c2b14628ef4f8ce9b3fdc5022073649a14971568a1cd2aa84b5dd404645f29e49882f60a9642850539443872fe012102a41e4348bb233e40cf3a3402e2dc92a31b69ef56090fff242aa7e4bff828929fffffffff1d3c389af5fdd047e307e5d5f87656bb2ef0c40b6ee879d342a59192090d3fbc000000006b483045022100dc7e0445fe98f3e76d68906c640ecca597598a03b48e6b85d72918347b9da7330220340ce9e9533ea84375a1f2122b7868b8ab556da53f1e1af14d1a71b0b123aade012102a41e4348bb233e40cf3a3402e2dc92a31b69ef56090fff242aa7e4bff828929fffffffff1ed624bad3df9d3a7be56dcd5d97c996fccc78164f16f59658b33f8da8859deb000000006b483045022100ba2a55f55a37b6712dd25dbef411aed869190ef60a208b39d4bd8e0ce8635b4d02201976d63489e23205aab651a9def43d6b3a740ba06de2ecabc43504241a71f229012102a41e4348bb233e40cf3a3402e2dc92a31b69ef56090fff242aa7e4bff828929fffffffff24e5cb4893beb0bb60193dbe11a9778d07e127c1cbc939c0a0388b1013ef75d9000000006a47304402203c27eea34db0ba070bee38d625d2cfcec1a0f5d8a9124023c84e9963d37f6145022015f7657cc57be515e6aa43c93c73457f5583b7c90c0af4e8a2f913257df27b0b012102a41e4348bb233e40cf3a3402e2dc92a31b69ef56090fff242aa7e4bff828929fffffffff997e6738c45eaf7af8bed7dc09e258139bffb0d2be8b4167473b6943adc0b28b000000006a47304402202d4c6df39b725d571d67bef14f0c6baa0cf4b93aa54aac2d2a15d3d940510d0602203643162545d5b63c007986627a317ed962f4d5023e4c15e9636a4eede86930c7012102a41e4348bb233e40cf3a3402e2dc92a31b69ef56090fff242aa7e4bff828929fffffffffcff2021b6b0bcd2a8b38583539dc140b98da4f41ae1e4adb089dc2cf3b66d6c6000000006a473044022019d5264c99145c7203e690fb2f57b0e218af2761e024f9ec1b774c703939b96e02204c2430fc4ae0fa43afb19a722f7b5d706bf5f2d5ee85229cbdc7a7b26433f5fd012102a41e4348bb233e40cf3a3402e2dc92a31b69ef56090fff242aa7e4bff828929fffffffff018f73e606000000001976a914ec093b0943ec524769553e1b7261b67ecab47e8688ac00000000"
}
```
Breeze-1.0.0/Breeze.UI/ 0000775 0000000 0000000 00000000000 13334556736 0014473 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/.angular-cli.json 0000664 0000000 0000000 00000002151 13334556736 0017641 0 ustar 00root root 0000000 0000000 {
"project": {
"name": "Breeze",
"ejected": true
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"./node_modules/ngx-bootstrap/datepicker/bs-datepicker.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": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"component": {
}
}
}
Breeze-1.0.0/Breeze.UI/.editorconfig 0000664 0000000 0000000 00000000365 13334556736 0017154 0 ustar 00root root 0000000 0000000 # 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
Breeze-1.0.0/Breeze.UI/README.md 0000664 0000000 0000000 00000004364 13334556736 0015761 0 ustar 00root root 0000000 0000000 # Breeze.UI
Graphical User Interface for Stratis Breeze Wallet.
## Getting Started
Clone this repository locally:
``` bash
git clone https://www.github.com/stratisproject/breeze.git
```
Navigate to the Breeze UI in a terminal:
``` bash
cd ./Breeze/Breeze.UI
```
## Install NodeJS:
Download and install the latest Long Term Support (LTS) version of NodeJS at: https://nodejs.org/.
## Install dependencies with npm:
From within Breeze.UI directory run:
``` bash
npm install
```
There is an issue with `yarn` and `node_modules` that are only used in electron on the backend when the application is built by the packager. Please use `npm` as dependency manager.
If you want to generate Angular components with Angular-cli, you **MUST** install `@angular/cli` in npm global context.
If you have already installed a previous version of `angular-cli`, follow [Angular-cli documentation](https://github.com/angular/angular-cli), otherwise execute `sudo npm install -g @angular/cli` command.
## To build for development
#### Terminal Window 1
[Run the daemon](https://github.com/stratisproject/Breeze/blob/master/README.md#daemon-build)
#### Terminal Window 2
`npm start`
This will compile the Angular code and spawn the Electron process in parallel.
After compilation has completed the Electron UI will refresh.
#### Terminal Window 3, 4
If you want to seperate the build process from the Electron process you can use `npm run start:webpack` and `npm run electron:serve`.
## To build for production
- Using development variables (environments/index.ts) : `npm run electron:dev`
- Using production variables (environments/index.prod.ts) : `npm run electron:prod`
Your built files are in the /dist folder.
## Included Commands
|Command|Description|
|--|--|
|`npm run start:web`| Execute the app in the brower |
|`npm run package:linux`| Builds your application and creates an app consumable on linux system |
|`npm run package:windows`| On a Windows OS, builds your application and creates an app consumable in windows 32/64 bit systems |
|`npm run package:mac`| On a MAC OS, builds your application and generates a `.app` file of your application that can be run on Mac |
**The application is optimised. Only the files of /dist folder are included in the executable.**
Breeze-1.0.0/Breeze.UI/e2e/ 0000775 0000000 0000000 00000000000 13334556736 0015146 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/e2e/app.e2e-spec.ts 0000664 0000000 0000000 00000000425 13334556736 0017701 0 ustar 00root root 0000000 0000000 import { BreezePage } from './app.po';
describe('breeze App', function() {
let page: BreezePage;
beforeEach(() => {
page = new BreezePage();
});
it('title should be Breeze', () => {
page.navigateTo();
expect(page.getTitle()).toEqual('Breeze');
});
});
Breeze-1.0.0/Breeze.UI/e2e/app.po.ts 0000664 0000000 0000000 00000000433 13334556736 0016713 0 ustar 00root root 0000000 0000000 import { browser, element, by } from 'protractor';
export class BreezePage {
navigateTo() {
return browser.get('/');
}
getParagraphText() {
return element(by.css('app-root h1')).getText();
}
getTitle() {
let title: string;
return browser.getTitle();
}
}
Breeze-1.0.0/Breeze.UI/e2e/tsconfig.e2e.json 0000664 0000000 0000000 00000000373 13334556736 0020332 0 ustar 00root root 0000000 0000000 {
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"typeRoots": [
"../node_modules/@types"
],
"types":[
"jasmine",
"node"
]
}
} Breeze-1.0.0/Breeze.UI/electron-builder.json 0000664 0000000 0000000 00000002532 13334556736 0020627 0 ustar 00root root 0000000 0000000 {
"appId": "com.stratisplatform.breeze",
"productName": "Breeze Wallet",
"publish": null,
"directories": {
"app": "dist",
"output": "app-builds",
"buildResources": "dist/assets/images"
},
"win": {
"icon": "dist/assets/images/icon",
"target": [
"nsis"
],
"artifactName": "${productName}-v${version}-setup-${os}-${env.arch}.${ext}"
},
"linux": {
"icon": "dist/assets/images/",
"target": [
"deb",
"tar.gz"
],
"synopsis": "Breeze Wallet: Stratis' dual-currency full block light wallet with a strong focus on privacy.",
"category": "Utility",
"artifactName": "${productName}-v${version}-${os}-${arch}.${ext}"
},
"mac": {
"target": [
"dmg"
],
"category": "public.app-category.productivity",
"artifactName": "${productName}-v${version}-${os}-${arch}.${ext}"
},
"nsis": {
"oneClick": false,
"perMachine": true,
"allowToChangeInstallationDirectory": true,
"deleteAppDataOnUninstall": true,
"guid": "ed20df62-ff5a-4b83-a5e3-a361357c6e51",
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"license": "src/assets/images/license_en.txt"
},
"msi": {
"warningsAsErrors": false
},
"extraResources": [
"daemon/**/*",
"src/assets/images/breeze-logo-tray.png",
"src/assets/images/license_en.txt"
]
}
Breeze-1.0.0/Breeze.UI/karma.conf.js 0000664 0000000 0000000 00000002330 13334556736 0017046 0 ustar 00root root 0000000 0000000 // 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-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
files: [
{ pattern: './src/test.ts', watched: false }
],
preprocessors: {
'./src/test.ts': ['@angular/cli']
},
mime: {
'text/x-typescript': ['ts','tsx']
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['progress', 'coverage-istanbul']
: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};
Breeze-1.0.0/Breeze.UI/main.ts 0000664 0000000 0000000 00000016524 13334556736 0015777 0 ustar 00root root 0000000 0000000 const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
const nativeImage = require('electron').nativeImage
const path = require('path');
const url = require('url');
const os = require('os');
let serve;
let testnet;
const args = process.argv.slice(1);
serve = args.some(val => val === "--serve" || val === "-serve");
testnet = args.some(val => val === "--testnet" || val === "-testnet");
if (args.some(val => val === "--mainnet" || val === "-mainnet")) {
testnet = false;
}
if (serve) {
require('electron-reload')(__dirname, {
electron: require('${__dirname}/../../node_modules/electron')
});
}
require('electron-context-menu')({
showInspectElement: serve
});
// 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: 1200,
height: 650,
frame: true,
minWidth: 1200,
minHeight: 650,
title: "Breeze Wallet"
});
// and load the index.html of the app.
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, '/index.html'),
protocol: 'file:',
slashes: true
}));
if (serve) {
mainWindow.webContents.openDevTools();
}
// 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;
});
// Emitted when the window is going to close.
mainWindow.on('close', function () {
})
};
// 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 () {
if (serve) {
console.log("Breeze UI was started in development mode. This requires the user to be running the Breeze Daemon himself.")
}
else {
startBitcoinApi();
startStratisApi();
}
createTray();
createWindow();
if (os.platform() === 'darwin'){
createMenu();
}
});
app.on('before-quit', function () {
closeBitcoinApi(),
closeStratisApi();
});
// 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 closeBitcoinApi() {
// if (process.platform !== 'darwin' && !serve) {
if (!serve) {
var http1 = require('http');
const options1 = {
hostname: 'localhost',
port: 37220,
path: '/api/node/shutdown',
method: 'POST'
};
const req = http1.request(options1, (res) => {});
req.write('');
req.end();
}
};
function closeStratisApi() {
// if (process.platform !== 'darwin' && !serve) {
if (process.platform !== 'darwin' && !serve) {
var http2 = require('http');
const options2 = {
hostname: 'localhost',
port: 37221,
path: '/api/node/shutdown',
method: 'POST'
};
const req = http2.request(options2, (res) => {});
req.write('');
req.end();
}
};
function startBitcoinApi() {
var bitcoinProcess;
const spawnBitcoin = require('child_process').spawn;
//Start Breeze Bitcoin Daemon
let apiPath = path.resolve(__dirname, 'assets//daemon//Stratis.BreezeD');
if (os.platform() === 'win32') {
apiPath = path.resolve(__dirname, '..\\..\\resources\\daemon\\Stratis.BreezeD.exe');
} else if(os.platform() === 'linux') {
apiPath = path.resolve(__dirname, '..//..//resources//daemon//Stratis.BreezeD');
} else {
apiPath = path.resolve(__dirname, '..//..//resources//daemon//Stratis.BreezeD');
}
if(!testnet) {
bitcoinProcess = spawnBitcoin(apiPath, {
detached: true
});
} else if (testnet) {
bitcoinProcess = spawnBitcoin(apiPath, ['-testnet'], {
detached: true
});
}
bitcoinProcess.stdout.on('data', (data) => {
writeLog(`Bitcoin: ${data}`);
});
}
function startStratisApi() {
var stratisProcess;
const spawnStratis = require('child_process').spawn;
//Start Breeze Stratis Daemon
let apiPath = path.resolve(__dirname, 'assets//daemon//Stratis.BreezeD');
if (os.platform() === 'win32') {
apiPath = path.resolve(__dirname, '..\\..\\resources\\daemon\\Stratis.BreezeD.exe');
} else if(os.platform() === 'linux') {
apiPath = path.resolve(__dirname, '..//..//resources//daemon//Stratis.BreezeD');
} else {
apiPath = path.resolve(__dirname, '..//..//resources//daemon//Stratis.BreezeD');
}
if (!testnet) {
stratisProcess = spawnStratis(apiPath, ['stratis'], {
detached: true
});
} else if (testnet) {
stratisProcess = spawnStratis(apiPath, ['stratis', '-testnet'], {
detached: true
});
}
stratisProcess.stdout.on('data', (data) => {
writeLog(`Stratis: ${data}`);
});
}
function createTray() {
//Put the app in system tray
const Menu = electron.Menu;
const Tray = electron.Tray;
let trayIcon;
if (serve) {
trayIcon = nativeImage.createFromPath('./src/assets/images/breeze-logo-tray.png');
} else {
trayIcon = nativeImage.createFromPath(path.resolve(__dirname, '../../resources/src/assets/images/breeze-logo-tray.png'));
}
let systemTray = new Tray(trayIcon);
const contextMenu = Menu.buildFromTemplate([
{
label: 'Hide/Show',
click: function() {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
}
},
{
label: 'Exit',
click: function() {
app.quit();
}
}
]);
systemTray.setToolTip('Breeze Wallet');
systemTray.setContextMenu(contextMenu);
systemTray.on('click', function() {
if (!mainWindow.isVisible()) {
mainWindow.show();
}
if (!mainWindow.isFocused()) {
mainWindow.focus();
}
});
app.on('window-all-closed', function () {
if (systemTray) systemTray.destroy();
});
};
function writeLog(msg) {
console.log(msg);
};
function createMenu() {
const Menu = electron.Menu;
// Create the Application's main menu
var menuTemplate = [{
label: "Application",
submenu: [
{ label: "About Application", selector: "orderFrontStandardAboutPanel:" },
{ type: "separator" },
{ label: "Quit", accelerator: "Command+Q", click: function() { app.quit(); }}
]}, {
label: "Edit",
submenu: [
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
{ label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
{ type: "separator" },
{ label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
{ label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
{ label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
{ label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }
]}
];
Menu.setApplicationMenu(Menu.buildFromTemplate(menuTemplate));
};
Breeze-1.0.0/Breeze.UI/package.js 0000664 0000000 0000000 00000002717 13334556736 0016433 0 ustar 00root root 0000000 0000000 "use strict";
var packager = require('electron-packager');
const pkg = require('./package.json');
const argv = require('minimist')(process.argv.slice(1));
const appName = argv.name || pkg.name;
const buildVersion = pkg.version || '1.0';
const shouldUseAsar = argv.asar || false;
const shouldBuildAll = argv.all || false;
const arch = argv.arch || 'all';
const platform = argv.platform || 'darwin';
const path = argv.path || 'app-builds';
const DEFAULT_OPTS = {
dir: './dist',
name: "Breeze",
asar: shouldUseAsar,
buildVersion: buildVersion
};
pack(platform, arch, path, function done(err, appPath) {
if (err) {
console.log(err);
} else {
console.log('Application packaged successfully!', appPath);
}
});
function pack(plat, arch, path, cb) {
// there is no darwin ia32 electron
if (plat === 'darwin' && arch === 'ia32') return;
let icon = 'src/assets/images/icon';
if (icon) {
DEFAULT_OPTS.icon = icon + (() => {
let extension = '.png';
if (plat === 'darwin') {
extension = '.icns';
} else if (plat === 'win32') {
extension = '.ico';
}
return extension;
})();
}
const opts = Object.assign({}, DEFAULT_OPTS, {
platform: plat,
arch,
prune: true,
overwrite: true,
all: shouldBuildAll,
out: path
});
console.log(opts)
packager(opts, cb);
}
Breeze-1.0.0/Breeze.UI/package.json 0000664 0000000 0000000 00000010530 13334556736 0016760 0 ustar 00root root 0000000 0000000 {
"name": "BreezeWallet",
"description": "Breeze Wallet: Stratis' dual-currency full block light wallet with a strong focus on privacy.",
"version": "1.0.0",
"author": {
"name": "Stratis Group",
"email": "info@stratisplatform.com"
},
"license": "MIT",
"homepage": "https://github.com/stratisproject/breeze",
"keywords": [
"breeze",
"ui",
"stratis",
"bitcoin",
"angular",
"electron",
"typescript",
"scss",
"bootstrap"
],
"main": "main.js",
"scripts": {
"ng": "ng",
"lint": "ng lint",
"start": "npm-run-all --parallel webpack:watch electron:serve",
"webpack:watch": "webpack --watch",
"build:electron:main": "tsc main.ts --outDir dist && copyfiles package.json dist && cd dist && npm install --prod && cd ..",
"build": "webpack --display-error-details && npm run build:electron:main",
"build:prod": "cross-env NODE_ENV=production npm run build",
"build:styling": "node-sass --output-style expanded --source-map true --precision 6 ./src/scss/bootstrap.scss ./src/styles.css",
"electron:serve": "npm run build:electron:main && electron ./dist --serve",
"electron:test": "electron ./dist",
"electron:dev": "npm run build && electron ./dist",
"electron:prod": "npm run build:prod && electron ./dist",
"package:linux": "npm run build:prod && node package.js --platform=linux --arch=x64",
"package:windows": "npm run build:prod && node package.js --platform=win32 --arch=ia32",
"package:winsetup": "npm run build:prod && npx electron-builder build --windows",
"package:mac": "npm run build:prod && node package.js --platform=darwin --arch=x64",
"test": "karma start ./karma.conf.js",
"pree2e": "webdriver-manager update --standalone false --gecko false --quiet && npm run build",
"e2e": "protractor ./protractor.conf.js"
},
"private": true,
"dependencies": {
"@angular/animations": "5.1.0",
"@angular/common": "5.1.0",
"@angular/compiler": "5.1.0",
"@angular/core": "5.1.0",
"@angular/forms": "5.1.0",
"@angular/http": "5.1.0",
"@angular/platform-browser": "5.1.0",
"@angular/platform-browser-dynamic": "5.1.0",
"@angular/platform-server": "5.1.0",
"@angular/router": "5.1.0",
"@ng-bootstrap/ng-bootstrap": "1.0.0-beta.7",
"bootstrap": "4.0.0-beta",
"core-js": "2.5.3",
"electron-context-menu": "0.9.1",
"enhanced-resolve": "3.4.1",
"ngx-bootstrap": "2.0.0-beta.11",
"ngx-clipboard": "9.0.0",
"rxjs": "5.5.5",
"zone.js": "0.8.18"
},
"devDependencies": {
"@angular/cli": "^1.7.4",
"@angular/compiler-cli": "5.1.0",
"@angular/language-service": "5.1.0",
"@types/core-js": "0.9.36",
"@types/jasmine": "2.6.0",
"@types/node": "7.0.7",
"autoprefixer": "7.2.2",
"circular-dependency-plugin": "4.3.0",
"codelyzer": "4.0.2",
"copy-webpack-plugin": "4.2.3",
"copyfiles": "1.2.0",
"cross-env": "5.1.1",
"css-loader": "0.28.7",
"cssnano": "3.10.0",
"electron": "1.7.9",
"electron-builder": "19.49.0",
"electron-packager": "10.1.0",
"electron-reload": "1.2.2",
"exports-loader": "0.6.4",
"file-loader": "1.1.5",
"html-loader": "0.5.1",
"html-webpack-plugin": "2.30.1",
"istanbul-instrumenter-loader": "3.0.0",
"jasmine-core": "2.8.0",
"jasmine-spec-reporter": "4.2.1",
"jquery": "3.2.1",
"json-loader": "0.5.7",
"karma": "1.7.1",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "1.3.0",
"karma-jasmine": "1.1.1",
"karma-jasmine-html-reporter": "0.2.2",
"karma-sourcemap-loader": "0.3.7",
"less-loader": "4.0.5",
"minimist": "1.2.0",
"mkdirp": "0.5.1",
"node-sass": "4.7.2",
"npm-run-all": "4.1.2",
"npx": "9.7.1",
"popper.js": "1.12.9",
"postcss-custom-properties": "^7.0.0",
"postcss-loader": "2.0.9",
"postcss-url": "7.3.0",
"protractor": "5.2.1",
"raw-loader": "0.5.1",
"sass-loader": "6.0.6",
"script-loader": "0.7.2",
"source-map-loader": "0.2.3",
"style-loader": "0.19.0",
"stylus-loader": "3.0.1",
"ts-node": "4.0.1",
"tslint": "5.8.0",
"typescript": "2.6.2",
"uglifyjs-webpack-plugin": "1.1.2",
"url-loader": "0.6.2",
"webdriver-manager": "12.0.6",
"webpack": "3.10.0",
"webpack-concat-plugin": "2.3.1",
"webpack-dev-server": "2.9.7"
}
}
Breeze-1.0.0/Breeze.UI/postcss.config.js 0000664 0000000 0000000 00000000024 13334556736 0017767 0 ustar 00root root 0000000 0000000 module.exports = {}; Breeze-1.0.0/Breeze.UI/protractor.conf.js 0000664 0000000 0000000 00000001703 13334556736 0020155 0 ustar 00root root 0000000 0000000 // Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 25000,
getPageTimeout: 15000,
delayBrowserTimeInSeconds: 0,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome',
chromeOptions: {
binary: './node_modules/electron/dist/electron.exe',
args: ['--test-type=webdriver', 'app=dist/main.js']
}
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine2',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
},
onPrepare() {
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
Breeze-1.0.0/Breeze.UI/src/ 0000775 0000000 0000000 00000000000 13334556736 0015262 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/ 0000775 0000000 0000000 00000000000 13334556736 0016042 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/app-routing.module.ts 0000664 0000000 0000000 00000001113 13334556736 0022137 0 ustar 00root root 0000000 0000000 import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LoginComponent } from './login/login.component';
const routes: Routes = [
{ path: '', redirectTo: 'login', pathMatch: 'full'},
{ path: 'login', component: LoginComponent},
{ path: 'setup', loadChildren: 'app/setup/setup.module#SetupModule'},
{ path: 'wallet', loadChildren: 'app/wallet/wallet.module#WalletModule'}
];
@NgModule({
imports: [ RouterModule.forRoot(routes, {useHash: true}) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
Breeze-1.0.0/Breeze.UI/src/app/app.component.css 0000664 0000000 0000000 00000000000 13334556736 0021323 0 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/app.component.html 0000664 0000000 0000000 00000003430 13334556736 0021511 0 ustar 00root root 0000000 0000000
Breeze-1.0.0/Breeze.UI/src/app/app.component.spec.ts 0000664 0000000 0000000 00000001215 13334556736 0022123 0 ustar 00root root 0000000 0000000 /* tslint:disable:no-unused-variable */
import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { RouterTestingModule } from '@angular/router/testing';
describe('AppComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
imports: [
RouterTestingModule
]
});
TestBed.compileComponents();
});
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
});
Breeze-1.0.0/Breeze.UI/src/app/app.component.ts 0000664 0000000 0000000 00000002402 13334556736 0021171 0 ustar 00root root 0000000 0000000 import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { ApiService } from './shared/services/api.service';
import { remote } from 'electron';
import 'rxjs/add/operator/retryWhen';
import 'rxjs/add/operator/delay';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
constructor(private router: Router, private apiService: ApiService, private titleService: Title) {}
private errorMessage: any;
private responseMessage: any;
public loading: boolean = true;
ngOnInit() {
this.setTitle();
this.apiService.getWalletFiles().retryWhen(errors => errors.delay(2000)).subscribe(() => this.checkStratisDaemon());
}
private checkStratisDaemon() {
this.apiService.getStratisWalletFiles().retryWhen(errors => errors.delay(2000)).subscribe(() => this.startApp());
}
private startApp() {
this.loading = false;
this.router.navigate(['/login']);
}
private setTitle() {
const applicationName = "Stratis Breeze Wallet";
const newTitle = applicationName + " v" + remote.app.getVersion();
this.titleService.setTitle(newTitle);
}
}
Breeze-1.0.0/Breeze.UI/src/app/app.module.ts 0000664 0000000 0000000 00000004271 13334556736 0020462 0 ustar 00root root 0000000 0000000 import { NgModule } from '@angular/core';
import { BrowserModule, Title } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { HttpModule } from '@angular/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { ClipboardModule } from 'ngx-clipboard';
import { SharedModule } from './shared/shared.module';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
import { GenericModalComponent } from './shared/components/generic-modal/generic-modal.component';
import { ApiService } from './shared/services/api.service';
import { GlobalService } from './shared/services/global.service';
import { ModalService } from './shared/services/modal.service';
import { NavigationService } from './shared/services/navigation.service';
import { SendComponent } from './wallet/send/send.component';
import { SendConfirmationComponent } from './wallet/send/send-confirmation/send-confirmation.component';
import { ReceiveComponent } from './wallet/receive/receive.component';
import { TransactionDetailsComponent } from './wallet/transaction-details/transaction-details.component';
import { LogoutConfirmationComponent } from './wallet/logout-confirmation/logout-confirmation.component';
@NgModule({
imports: [
AppRoutingModule,
BrowserModule,
BrowserAnimationsModule,
ClipboardModule,
ReactiveFormsModule,
FormsModule,
HttpModule,
NgbModule.forRoot(),
SharedModule.forRoot()
],
declarations: [
AppComponent,
GenericModalComponent,
LoginComponent,
LogoutConfirmationComponent,
SendComponent,
SendConfirmationComponent,
ReceiveComponent,
TransactionDetailsComponent
],
entryComponents: [
GenericModalComponent,
SendComponent,
SendConfirmationComponent,
ReceiveComponent,
TransactionDetailsComponent,
LogoutConfirmationComponent
],
providers: [ NavigationService, ApiService, GlobalService, ModalService, Title ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Breeze-1.0.0/Breeze.UI/src/app/login/ 0000775 0000000 0000000 00000000000 13334556736 0017152 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/login/login.component.css 0000664 0000000 0000000 00000000000 13334556736 0022763 0 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/login/login.component.html 0000664 0000000 0000000 00000042364 13334556736 0023162 0 ustar 00root root 0000000 0000000
Welcome to Breeze
Please choose the wallet you would like to open:
If you would like to create or restore a wallet please click the button below.
Looks like you're new here.
Please create or restore a wallet.
Breeze-1.0.0/Breeze.UI/src/app/login/login.component.spec.ts 0000664 0000000 0000000 00000001155 13334556736 0023566 0 ustar 00root root 0000000 0000000 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoginComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/login/login.component.ts 0000664 0000000 0000000 00000014556 13334556736 0022646 0 ustar 00root root 0000000 0000000 import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { GlobalService } from '../shared/services/global.service';
import { ApiService } from '../shared/services/api.service';
import { ModalService } from '../shared/services/modal.service';
import { WalletLoad } from '../shared/classes/wallet-load';
import { WalletInfo } from '../shared/classes/wallet-info';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private globalService: GlobalService, private apiService: ApiService, private genericModalService: ModalService, private router: Router, private fb: FormBuilder) {
this.buildDecryptForm();
}
public hasWallet: boolean = false;
public isDecrypting = false;
private openWalletForm: FormGroup;
private wallets: [string];
ngOnInit() {
this.getWalletFiles();
}
private buildDecryptForm(): void {
this.openWalletForm = this.fb.group({
"selectWallet": ["", Validators.required],
"password": ["", Validators.required]
});
this.openWalletForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged();
}
onValueChanged(data?: any) {
if (!this.openWalletForm) { return; }
const form = this.openWalletForm;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
formErrors = {
'password': ''
};
validationMessages = {
'password': {
'required': 'Please enter your password.'
}
};
private getWalletFiles() {
this.apiService.getWalletFiles()
.subscribe(
response => {
if (response.status >= 200 && response.status < 400) {
let responseMessage = response.json();
this.wallets = responseMessage.walletsFiles;
this.globalService.setWalletPath(responseMessage.walletsPath);
if (this.wallets.length > 0) {
this.hasWallet = true;
for (let wallet in this.wallets) {
this.wallets[wallet] = this.wallets[wallet].slice(0, -12);
}
this.updateWalletFileDisplay(this.wallets[0]);
} else {
this.hasWallet = false;
}
}
},
error => {
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
}
}
}
)
;
}
private updateWalletFileDisplay(walletName: string) {
this.openWalletForm.patchValue({selectWallet: walletName})
}
private onCreateClicked() {
this.router.navigate(['/setup']);
}
private onEnter() {
if (this.openWalletForm.valid) {
this.onDecryptClicked();
}
}
private onDecryptClicked() {
this.isDecrypting = true;
this.globalService.setWalletName(this.openWalletForm.get("selectWallet").value);
this.getCurrentNetwork();
let walletLoad = new WalletLoad(
this.openWalletForm.get("selectWallet").value,
this.openWalletForm.get("password").value
);
this.loadWallets(walletLoad);
}
private loadWallets(walletLoad: WalletLoad) {
this.apiService.loadBitcoinWallet(walletLoad)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400) {
this.globalService.setWalletName(walletLoad.name);
}
},
error => {
this.isDecrypting = false;
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
}
}
},
() => this.loadStratisWallet(walletLoad)
)
;
}
private loadStratisWallet(walletLoad: WalletLoad) {
this.apiService.loadStratisWallet(walletLoad)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400) {
// Navigate to the wallet section
this.router.navigate(['/wallet']);
}
},
error => {
this.isDecrypting = false;
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
}
}
}
)
;
}
private getCurrentNetwork() {
let walletInfo = new WalletInfo(this.globalService.getWalletName())
this.apiService.getGeneralInfoOnce(walletInfo)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400) {
let responseMessage = response.json();
this.globalService.setNetwork(responseMessage.network);
if (responseMessage.network === "Main") {
this.globalService.setCoinName("Bitcoin");
this.globalService.setCoinUnit("BTC");
} else if (responseMessage.network === "TestNet") {
this.globalService.setCoinName("TestBitcoin");
this.globalService.setCoinUnit("TBTC");
}
}
},
error => {
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
}
}
}
)
;
}
}
Breeze-1.0.0/Breeze.UI/src/app/setup/ 0000775 0000000 0000000 00000000000 13334556736 0017202 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/create/ 0000775 0000000 0000000 00000000000 13334556736 0020445 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/create/confirm-mnemonic/ 0000775 0000000 0000000 00000000000 13334556736 0023705 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/create/confirm-mnemonic/confirm-mnemonic.component.css 0000664 0000000 0000000 00000000000 13334556736 0031646 0 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/create/confirm-mnemonic/confirm-mnemonic.component.html 0000664 0000000 0000000 00000004312 13334556736 0032034 0 ustar 00root root 0000000 0000000
Confirm secret words
Please enter the corresponding secret words below.
Breeze-1.0.0/Breeze.UI/src/app/setup/create/confirm-mnemonic/confirm-mnemonic.component.spec.ts 0000664 0000000 0000000 00000001264 13334556736 0032452 0 ustar 00root root 0000000 0000000 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ConfirmMnemonicComponent } from './confirm-mnemonic.component';
describe('ConfirmMnemonicComponent', () => {
let component: ConfirmMnemonicComponent;
let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ConfirmMnemonicComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ConfirmMnemonicComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/setup/create/confirm-mnemonic/confirm-mnemonic.component.ts 0000664 0000000 0000000 00000014470 13334556736 0031524 0 ustar 00root root 0000000 0000000 import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { GlobalService } from '../../../shared/services/global.service';
import { ApiService } from '../../../shared/services/api.service';
import { ModalService } from '../../../shared/services/modal.service';
import { WalletCreation } from '../../../shared/classes/wallet-creation';
import { Subscription } from 'rxjs/Subscription';
import { Subscribable } from 'rxjs/Observable';
@Component({
selector: 'app-confirm-mnemonic',
templateUrl: './confirm-mnemonic.component.html',
styleUrls: ['./confirm-mnemonic.component.css']
})
export class ConfirmMnemonicComponent implements OnInit {
constructor(private globalService: GlobalService, private apiService: ApiService, private genericModalService: ModalService, private route: ActivatedRoute, private router: Router, private fb: FormBuilder) {
this.buildMnemonicForm();
}
private subscription: Subscription;
private newWallet: WalletCreation;
public mnemonicForm: FormGroup;
public matchError: string = "";
public isCreating: boolean;
ngOnInit() {
this.subscription = this.route.queryParams.subscribe(params => {
this.newWallet = new WalletCreation(
params["name"],
params["mnemonic"],
params["password"]
)
});
}
private buildMnemonicForm(): void {
this.mnemonicForm = this.fb.group({
"word1": ["",
Validators.compose([
Validators.required,
Validators.minLength(1),
Validators.maxLength(24),
Validators.pattern(/^[a-zA-Z]*$/)
])
],
"word2": ["",
Validators.compose([
Validators.required,
Validators.minLength(1),
Validators.maxLength(24),
Validators.pattern(/^[a-zA-Z]*$/)
])
],
"word3": ["",
Validators.compose([
Validators.required,
Validators.minLength(1),
Validators.maxLength(24),
Validators.pattern(/^[a-zA-Z]*$/)
])
]
});
this.mnemonicForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged();
}
onValueChanged(data?: any) {
if (!this.mnemonicForm) { return; }
const form = this.mnemonicForm;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
this.matchError = "";
}
formErrors = {
'word1': '',
'word2': '',
'word3': ''
};
validationMessages = {
'word1': {
'required': 'This secret word is required.',
'minlength': 'A secret word must be at least one character long',
'maxlength': 'A secret word can not be longer than 24 characters',
'pattern': 'Please enter a valid scret word. [a-Z] are the only characters allowed.'
},
'word2': {
'required': 'This secret word is required.',
'minlength': 'A secret word must be at least one character long',
'maxlength': 'A secret word can not be longer than 24 characters',
'pattern': 'Please enter a valid scret word. [a-Z] are the only characters allowed.'
},
'word3': {
'required': 'This secret word is required.',
'minlength': 'A secret word must be at least one character long',
'maxlength': 'A secret word can not be longer than 24 characters',
'pattern': 'Please enter a valid scret word. [a-Z] are the only characters allowed.'
}
};
public onConfirmClicked() {
this.checkMnemonic();
if (this.checkMnemonic()) {
this.isCreating = true;
this.createWallets(this.newWallet);
}
}
public onBackClicked() {
this.router.navigate(['/setup/create/show-mnemonic'], { queryParams : { name: this.newWallet.name, mnemonic: this.newWallet.mnemonic, password: this.newWallet.password }});
}
private checkMnemonic(): boolean {
let mnemonic = this.newWallet.mnemonic;
let mnemonicArray = mnemonic.split(" ");
if (this.mnemonicForm.get("word1").value.trim() === mnemonicArray[3] && this.mnemonicForm.get("word2").value.trim() === mnemonicArray[7] && this.mnemonicForm.get("word3").value.trim() === mnemonicArray[11]) {
return true;
} else {
this.matchError = "The secret words do not match."
return false;
}
}
private createWallets(wallet: WalletCreation) {
this.apiService
.createBitcoinWallet(wallet)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
// Bitcoin wallet created
}
},
error => {
console.log(error);
this.isCreating = false;
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
this.router.navigate(['/setup/create']);
}
}
},
() => this.createStratisWallet(wallet)
)
;
}
private createStratisWallet(wallet: WalletCreation) {
this.apiService
.createStratisWallet(wallet)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
this.genericModalService.openModal("Wallet Created", "Your wallet has been created.
Keep your secret words and password safe!");
this.router.navigate(['']);
}
},
error => {
this.isCreating = false;
console.log(error);
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
this.router.navigate(['/setup/create']);
}
}
}
)
;
}
}
Breeze-1.0.0/Breeze.UI/src/app/setup/create/create.component.css 0000664 0000000 0000000 00000000000 13334556736 0024411 0 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/create/create.component.html 0000664 0000000 0000000 00000004452 13334556736 0024604 0 ustar 00root root 0000000 0000000
Create a new wallet
Breeze-1.0.0/Breeze.UI/src/app/setup/create/create.component.spec.ts 0000664 0000000 0000000 00000001164 13334556736 0025214 0 ustar 00root root 0000000 0000000 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CreateComponent } from './create.component';
describe('CreateComponent', () => {
let component: CreateComponent;
let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CreateComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CreateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/setup/create/create.component.ts 0000664 0000000 0000000 00000010704 13334556736 0024263 0 ustar 00root root 0000000 0000000 import { Component, Injectable, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { GlobalService } from '../../shared/services/global.service';
import { ApiService } from '../../shared/services/api.service';
import { ModalService } from '../../shared/services/modal.service';
import { PasswordValidationDirective } from '../../shared/directives/password-validation.directive';
import { WalletCreation } from '../../shared/classes/wallet-creation';
import { Mnemonic } from '../../shared/classes/mnemonic';
@Component({
selector: 'create-component',
templateUrl: './create.component.html',
styleUrls: ['./create.component.css'],
})
export class CreateComponent implements OnInit {
constructor(private globalService: GlobalService, private apiService: ApiService, private genericModalService: ModalService, private router: Router, private fb: FormBuilder) {
this.buildCreateForm();
}
public createWalletForm: FormGroup;
private newWallet: WalletCreation;
private mnemonic: string;
ngOnInit() {
this.getNewMnemonic();
}
private buildCreateForm(): void {
this.createWalletForm = this.fb.group({
"walletName": ["",
Validators.compose([
Validators.required,
Validators.minLength(1),
Validators.maxLength(24),
Validators.pattern(/^[a-zA-Z0-9]*$/)
])
],
"walletPassword": ["",
Validators.required,
// Validators.compose([
// Validators.required,
// Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{10,})/)])
],
"walletPasswordConfirmation": ["", Validators.required],
"selectNetwork": ["test", Validators.required]
}, {
validator: PasswordValidationDirective.MatchPassword
});
this.createWalletForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged();
}
onValueChanged(data?: any) {
if (!this.createWalletForm) { return; }
const form = this.createWalletForm;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
formErrors = {
'walletName': '',
'walletPassword': '',
'walletPasswordConfirmation': ''
};
validationMessages = {
'walletName': {
'required': 'A wallet name is required.',
'minlength': 'A wallet name must be at least one character long.',
'maxlength': 'A wallet name cannot be more than 24 characters long.',
'pattern': 'Please enter a valid wallet name. [a-Z] and [0-9] are the only characters allowed.'
},
'walletPassword': {
'required': 'A password is required.',
'pattern': 'A password must be at least 10 characters long and contain one lowercase and uppercase alphabetical character and a number.'
},
'walletPasswordConfirmation': {
'required': 'Confirm your password.',
'walletPasswordConfirmation': 'Passwords do not match.'
}
};
public onBackClicked() {
this.router.navigate(["/setup"]);
}
public onContinueClicked() {
if (this.mnemonic) {
this.newWallet = new WalletCreation(
this.createWalletForm.get("walletName").value,
this.mnemonic,
this.createWalletForm.get("walletPassword").value,
);
this.router.navigate(['/setup/create/show-mnemonic'], { queryParams : { name: this.newWallet.name, mnemonic: this.newWallet.mnemonic, password: this.newWallet.password }});
//this.createWallets(this.newWallet);
}
}
private getNewMnemonic() {
this.apiService
.getNewMnemonic()
.subscribe(
response => {
if (response.status >= 200 && response.status < 400){
this.mnemonic = response.json();
}
},
error => {
console.log(error);
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
this.genericModalService.openModal(null, error.json().errors[0].message);
}
}
}
)
;
}
}
Breeze-1.0.0/Breeze.UI/src/app/setup/create/show-mnemonic/ 0000775 0000000 0000000 00000000000 13334556736 0023230 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/create/show-mnemonic/show-mnemonic.component.css 0000664 0000000 0000000 00000000000 13334556736 0030514 0 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/create/show-mnemonic/show-mnemonic.component.html 0000664 0000000 0000000 00000002406 13334556736 0030704 0 ustar 00root root 0000000 0000000
Secret words
Please write down your secret words and password.
You will need both to recover your wallet in the future.
Write down your secret words and password before you continue
Breeze-1.0.0/Breeze.UI/src/app/setup/create/show-mnemonic/show-mnemonic.component.spec.ts 0000664 0000000 0000000 00000001237 13334556736 0031320 0 ustar 00root root 0000000 0000000 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ShowMnemonicComponent } from './show-mnemonic.component';
describe('ShowMnemonicComponent', () => {
let component: ShowMnemonicComponent;
let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ShowMnemonicComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ShowMnemonicComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/setup/create/show-mnemonic/show-mnemonic.component.ts 0000664 0000000 0000000 00000002615 13334556736 0030370 0 ustar 00root root 0000000 0000000 import { Component, OnInit, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { WalletCreation } from '../../../shared/classes/wallet-creation';
import { Subscription } from 'rxjs/Subscription';
@Component({
selector: 'app-show-mnemonic',
templateUrl: './show-mnemonic.component.html',
styleUrls: ['./show-mnemonic.component.css']
})
export class ShowMnemonicComponent implements OnInit, OnDestroy {
constructor(private route: ActivatedRoute, private router: Router) { }
private parameters: any;
private mnemonic: string;
private subscription: Subscription;
private newWallet: WalletCreation;
public mnemonicArray: string[];
ngOnInit() {
this.subscription = this.route.queryParams.subscribe(params => {
this.newWallet = new WalletCreation(
params["name"],
params["mnemonic"],
params["password"]
)
});
this.showMnemonic();
}
private showMnemonic() {
this.mnemonic = this.newWallet.mnemonic;
this.mnemonicArray = this.mnemonic.split(" ");
}
public onContinueClicked() {
this.router.navigate(['/setup/create/confirm-mnemonic'], { queryParams : { name: this.newWallet.name, mnemonic: this.newWallet.mnemonic, password: this.newWallet.password }});
}
public onCancelClicked() {
this.router.navigate(['']);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
Breeze-1.0.0/Breeze.UI/src/app/setup/recover/ 0000775 0000000 0000000 00000000000 13334556736 0020647 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/recover/recover.component.css 0000664 0000000 0000000 00000000000 13334556736 0025015 0 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/recover/recover.component.html 0000664 0000000 0000000 00000005470 13334556736 0025211 0 ustar 00root root 0000000 0000000
Breeze-1.0.0/Breeze.UI/src/app/setup/recover/recover.component.spec.ts 0000664 0000000 0000000 00000001173 13334556736 0025620 0 ustar 00root root 0000000 0000000 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RecoverComponent } from './recover.component';
describe('RecoverComponent', () => {
let component: RecoverComponent;
let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ RecoverComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(RecoverComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/setup/recover/recover.component.ts 0000664 0000000 0000000 00000013746 13334556736 0024700 0 ustar 00root root 0000000 0000000 import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { Router } from '@angular/router';
import { BsDatepickerConfig } from 'ngx-bootstrap/datepicker';
import { GlobalService } from '../../shared/services/global.service';
import { ApiService } from '../../shared/services/api.service';
import { ModalService } from '../../shared/services/modal.service';
import { WalletRecovery } from '../../shared/classes/wallet-recovery';
@Component({
selector: 'app-recover',
templateUrl: './recover.component.html',
styleUrls: ['./recover.component.css']
})
export class RecoverComponent implements OnInit {
constructor(private globalService: GlobalService, private apiService: ApiService, private genericModalService: ModalService, private router: Router, private fb: FormBuilder) {
this.buildRecoverForm();
}
public recoverWalletForm: FormGroup;
public creationDate: Date;
public isRecovering: boolean = false;
public maxDate = new Date();
public bsConfig: Partial;
private walletRecovery: WalletRecovery;
ngOnInit() {
this.bsConfig = Object.assign({}, {showWeekNumbers: false, containerClass: 'theme-blue'});
}
private buildRecoverForm(): void {
this.recoverWalletForm = this.fb.group({
"walletName": ["", [
Validators.required,
Validators.minLength(1),
Validators.maxLength(24),
Validators.pattern(/^[a-zA-Z0-9]*$/)
]
],
"walletMnemonic": ["", Validators.required],
"walletDate": ["", Validators.required],
"walletPassword": ["", Validators.required],
"selectNetwork": ["test", Validators.required]
});
this.recoverWalletForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged();
}
onValueChanged(data?: any) {
if (!this.recoverWalletForm) { return; }
const form = this.recoverWalletForm;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
formErrors = {
'walletName': '',
'walletMnemonic': '',
'walletDate': '',
'walletPassword': '',
};
validationMessages = {
'walletName': {
'required': 'A wallet name is required.',
'minlength': 'A wallet name must be at least one character long.',
'maxlength': 'A wallet name cannot be more than 24 characters long.',
'pattern': 'Please enter a valid wallet name. [a-Z] and [0-9] are the only characters allowed.'
},
'walletMnemonic': {
'required': 'Please enter your 12 word phrase.'
},
'walletDate': {
'required': 'Please choose the date the wallet should sync from.'
},
'walletPassword': {
'required': 'A password is required.'
},
};
public onBackClicked() {
this.router.navigate(["/setup"]);
}
public onRecoverClicked(){
this.isRecovering = true;
let recoveryDate = new Date(this.recoverWalletForm.get("walletDate").value);
recoveryDate.setDate(recoveryDate.getDate() - 1);
this.walletRecovery = new WalletRecovery(
this.recoverWalletForm.get("walletName").value,
this.recoverWalletForm.get("walletMnemonic").value,
this.recoverWalletForm.get("walletPassword").value,
recoveryDate
);
this.recoverWallets(this.walletRecovery);
}
private recoverWallets(recoverWallet: WalletRecovery) {
let bitcoinErrorMessage = "";
this.apiService
.recoverBitcoinWallet(recoverWallet)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400) {
//Bitcoin Wallet Recovered
}
this.recoverStratisWallet(recoverWallet, bitcoinErrorMessage);
},
error => {
this.isRecovering = false;
console.log(error);
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
bitcoinErrorMessage = error.json().errors[0].message;
}
}
this.recoverStratisWallet(recoverWallet, bitcoinErrorMessage);
}
)
;
}
private recoverStratisWallet(recoverWallet: WalletRecovery, bitcoinErrorMessage: string){
let stratisErrorMessage = "";
this.apiService
.recoverStratisWallet(recoverWallet)
.subscribe(
response => {
if (response.status >= 200 && response.status < 400) {
let body = "Your wallet has been recovered. \nYou will be redirected to the decryption page.";
this.genericModalService.openModal("Wallet Recovered", body);
this.router.navigate([''])
}
this.AlertIfNeeded(bitcoinErrorMessage, stratisErrorMessage);
},
error => {
this.isRecovering = false;
console.log(error);
if (error.status === 0) {
this.genericModalService.openModal(null, null);
} else if (error.status >= 400) {
if (!error.json().errors[0]) {
console.log(error);
}
else {
stratisErrorMessage = error.json().errors[0].message;
}
}
this.AlertIfNeeded(bitcoinErrorMessage, stratisErrorMessage);
}
)
;
}
private AlertIfNeeded(bitcoinErrorMessage: string, stratisErrorMessage: string) {
if(bitcoinErrorMessage !== "" || stratisErrorMessage !== "") {
let errorMessage = "Bitcoin wallet recovery:
" + bitcoinErrorMessage + "
Stratis wallet recovery:
" + stratisErrorMessage;
this.genericModalService.openModal(null, errorMessage);
}
}
}
Breeze-1.0.0/Breeze.UI/src/app/setup/setup-routing.module.ts 0000664 0000000 0000000 00000001706 13334556736 0023667 0 ustar 00root root 0000000 0000000 import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SetupComponent } from './setup.component';
import { CreateComponent } from './create/create.component';
import { ShowMnemonicComponent } from './create/show-mnemonic/show-mnemonic.component';
import { ConfirmMnemonicComponent } from './create/confirm-mnemonic/confirm-mnemonic.component';
import { RecoverComponent } from './recover/recover.component';
const routes: Routes = [
{ path: '', redirectTo: 'setup', pathMatch: 'full'},
{ path: 'setup', component: SetupComponent },
{ path: 'create', component: CreateComponent },
{ path: 'create/show-mnemonic', component: ShowMnemonicComponent },
{ path: 'create/confirm-mnemonic', component: ConfirmMnemonicComponent },
{ path: 'recover', component: RecoverComponent }
];
@NgModule({
imports: [ RouterModule.forChild(routes) ],
exports: [ RouterModule ]
})
export class SetupRoutingModule {}
Breeze-1.0.0/Breeze.UI/src/app/setup/setup.component.css 0000664 0000000 0000000 00000000000 13334556736 0023043 0 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/setup/setup.component.html 0000664 0000000 0000000 00000002117 13334556736 0023232 0 ustar 00root root 0000000 0000000
Welcome
If you would like to create a new wallet, please click Create.
If you used Breeze before, please click Restore to recover your old wallet.
Breeze-1.0.0/Breeze.UI/src/app/setup/setup.component.ts 0000664 0000000 0000000 00000001104 13334556736 0022707 0 ustar 00root root 0000000 0000000 import { Component } from '@angular/core';
import {Location} from '@angular/common';
import { Router } from '@angular/router';
@Component({
selector: 'setup-component',
templateUrl: './setup.component.html',
styleUrls: ['./setup.component.css'],
})
export class SetupComponent {
constructor(private router: Router, private location: Location) {}
public onCreateClicked() {
this.router.navigate(['/setup/create']);
}
public onRecoverClicked() {
this.router.navigate(['/setup/recover']);
}
public onBackClicked() {
this.router.navigate(['']);
}
}
Breeze-1.0.0/Breeze.UI/src/app/setup/setup.module.ts 0000664 0000000 0000000 00000002036 13334556736 0022177 0 ustar 00root root 0000000 0000000 import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import { SetupComponent } from './setup.component';
import { CreateComponent } from './create/create.component';
import { SharedModule } from '../shared/shared.module';
import { SetupRoutingModule } from './setup-routing.module';
import { RecoverComponent } from './recover/recover.component';
import { ShowMnemonicComponent } from './create/show-mnemonic/show-mnemonic.component';
import { ConfirmMnemonicComponent } from './create/confirm-mnemonic/confirm-mnemonic.component';
@NgModule({
imports: [
BsDatepickerModule.forRoot(),
CommonModule,
ReactiveFormsModule,
SetupRoutingModule,
SharedModule.forRoot()
],
declarations: [
CreateComponent,
SetupComponent,
RecoverComponent,
ShowMnemonicComponent,
ConfirmMnemonicComponent
],
exports: [],
providers: []
})
export class SetupModule { }
Breeze-1.0.0/Breeze.UI/src/app/shared/ 0000775 0000000 0000000 00000000000 13334556736 0017310 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/shared/classes/ 0000775 0000000 0000000 00000000000 13334556736 0020745 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/shared/classes/fee-estimation.ts 0000664 0000000 0000000 00000001116 13334556736 0024225 0 ustar 00root root 0000000 0000000 export class FeeEstimation {
constructor(walletName: string, accountName: string, destinationAddress: string, amount: string, feeType: string, allowUnconfirmed: boolean) {
this.walletName = walletName;
this.accountName = accountName;
this.destinationAddress = destinationAddress;
this.amount = amount;
this.feeType = feeType;
this.allowUnconfirmed = allowUnconfirmed;
}
walletName: string;
accountName: string;
destinationAddress: string;
amount: string;
feeType: string;
allowUnconfirmed: boolean;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/mnemonic.ts 0000664 0000000 0000000 00000000056 13334556736 0023123 0 ustar 00root root 0000000 0000000 export class Mnemonic {
mnemonic: string;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/serialDisposable.ts 0000664 0000000 0000000 00000000574 13334556736 0024610 0 ustar 00root root 0000000 0000000 import { Subscription } from 'rxjs/Subscription';
export class SerialDisposable {
private subscription: Subscription;
set disposable(value: Subscription) {
this.dispose();
this.subscription = value;
}
dispose() {
if (this.subscription) {
this.subscription.unsubscribe();
this.subscription = null;
}
}
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/transaction-building.ts 0000664 0000000 0000000 00000001151 13334556736 0025433 0 ustar 00root root 0000000 0000000 export class TransactionBuilding {
constructor(walletName: string, accountName: string, password: string, destinationAddress: string, amount: string, feeType: string, allowUnconfirmed: boolean) {
this.walletName = walletName;
this.accountName = accountName;
this.password = password;
this.destinationAddress = destinationAddress;
this.amount = amount;
this.feeType = feeType;
this.allowUnconfirmed = allowUnconfirmed;
}
walletName: string;
accountName: string;
password: string;
destinationAddress: string;
amount: string;
feeType: string;
allowUnconfirmed: boolean;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/transaction-info.ts 0000664 0000000 0000000 00000001400 13334556736 0024566 0 ustar 00root root 0000000 0000000 export class TransactionInfo {
constructor(transactionType: string, transactionId: string, transactionAmount: number, transactionFee: number, transactionConfirmedInBlock: number, transactionTimestamp: number) {
this.transactionType = transactionType;
this.transactionId = transactionId;
this.transactionAmount = transactionAmount;
this.transactionFee = transactionFee;
this.transactionConfirmedInBlock = transactionConfirmedInBlock;
this.transactionTimestamp = transactionTimestamp;
}
public transactionType: string;
public transactionId: string;
public transactionAmount: number;
public transactionFee: number;
public transactionConfirmedInBlock?: number;
public transactionTimestamp: number;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/transaction-sending.ts 0000664 0000000 0000000 00000000152 13334556736 0025265 0 ustar 00root root 0000000 0000000 export class TransactionSending {
constructor(hex: string) {
this.hex = hex;
}
hex: string;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/wallet-creation.ts 0000664 0000000 0000000 00000000507 13334556736 0024411 0 ustar 00root root 0000000 0000000 export class WalletCreation {
constructor(name: string, mnemonic: string, password: string, folderPath: string = null ) {
this.name = name;
this.mnemonic = mnemonic;
this.password = password;
this.folderPath = folderPath;
}
name: string;
mnemonic: string;
password: string;
folderPath?: string;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/wallet-info.ts 0000664 0000000 0000000 00000000205 13334556736 0023533 0 ustar 00root root 0000000 0000000 export class WalletInfo {
constructor(walletName: string) {
this.walletName = walletName;
}
public walletName: string;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/wallet-load.ts 0000664 0000000 0000000 00000000424 13334556736 0023522 0 ustar 00root root 0000000 0000000 export class WalletLoad {
constructor(name: string, password: string, folderPath: string = null ) {
this.name = name;
this.password = password;
this.folderPath = folderPath;
}
public name: string;
public password: string;
public folderPath?: string;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/classes/wallet-recovery.ts 0000664 0000000 0000000 00000000642 13334556736 0024443 0 ustar 00root root 0000000 0000000 export class WalletRecovery {
constructor(walletName: string, mnemonic: string, password: string, creationDate: Date, folderPath: string = null) {
this.name = walletName;
this.mnemonic = mnemonic;
this.password = password;
this.creationDate = creationDate;
this.folderPath = folderPath;
}
mnemonic: string;
password: string;
name: string;
creationDate: Date;
folderPath?: string;
}
Breeze-1.0.0/Breeze.UI/src/app/shared/components/ 0000775 0000000 0000000 00000000000 13334556736 0021475 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/shared/components/generic-modal/ 0000775 0000000 0000000 00000000000 13334556736 0024203 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/shared/components/generic-modal/generic-modal.component.css 0000664 0000000 0000000 00000000000 13334556736 0031412 0 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/shared/components/generic-modal/generic-modal.component.html 0000664 0000000 0000000 00000001112 13334556736 0031573 0 ustar 00root root 0000000 0000000
Breeze-1.0.0/Breeze.UI/src/app/shared/components/generic-modal/generic-modal.component.spec.ts 0000664 0000000 0000000 00000001237 13334556736 0032216 0 ustar 00root root 0000000 0000000 import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { GenericModalComponent } from './generic-modal.component';
describe('GenericModalComponent', () => {
let component: GenericModalComponent;
let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GenericModalComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GenericModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/shared/components/generic-modal/generic-modal.component.ts 0000664 0000000 0000000 00000001076 13334556736 0031266 0 ustar 00root root 0000000 0000000 import { Component, OnInit, Input } from '@angular/core';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-generic-modal',
templateUrl: './generic-modal.component.html',
styleUrls: ['./generic-modal.component.css']
})
export class GenericModalComponent implements OnInit {
@Input() public title: string = "Something went wrong";
@Input() public body: string = "Something went wrong while connecting to the API. Please restart the application.";
constructor(public activeModal: NgbActiveModal) {}
ngOnInit() {
}
}
Breeze-1.0.0/Breeze.UI/src/app/shared/directives/ 0000775 0000000 0000000 00000000000 13334556736 0021451 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/shared/directives/auto-focus.directive.spec.ts 0000664 0000000 0000000 00000000355 13334556736 0027017 0 ustar 00root root 0000000 0000000 import { AutoFocusDirective } from './auto-focus.directive';
describe('AutoFocusDirective', () => {
it('should create an instance', () => {
const directive = new AutoFocusDirective();
expect(directive).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/shared/directives/auto-focus.directive.ts 0000664 0000000 0000000 00000000556 13334556736 0026071 0 ustar 00root root 0000000 0000000 import { Directive, Renderer, ElementRef, OnInit } from '@angular/core';
@Directive({
selector: '[myAutoFocus]'
})
export class AutoFocusDirective implements OnInit {
constructor(private renderer: Renderer, private elementRef: ElementRef) { }
ngOnInit() {
this.renderer.invokeElementMethod(
this.elementRef.nativeElement, 'focus', []
);
}
}
Breeze-1.0.0/Breeze.UI/src/app/shared/directives/password-validation.directive.spec.ts 0000664 0000000 0000000 00000000421 13334556736 0030716 0 ustar 00root root 0000000 0000000 import { PasswordValidationDirective } from './password-validation.directive';
describe('PasswordValidationDirective', () => {
it('should create an instance', () => {
const directive = new PasswordValidationDirective();
expect(directive).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/shared/directives/password-validation.directive.ts 0000664 0000000 0000000 00000001147 13334556736 0027773 0 ustar 00root root 0000000 0000000 import { Directive } from '@angular/core';
import { AbstractControl } from '@angular/forms';
@Directive({
selector: '[appPasswordValidation]'
})
export class PasswordValidationDirective {
constructor() { }
static MatchPassword(AC: AbstractControl) {
let password = AC.get('walletPassword').value;
let confirmPassword = AC.get('walletPasswordConfirmation').value;
if(confirmPassword !== password) {
AC.get('walletPasswordConfirmation').setErrors({ walletPasswordConfirmation: true });
} else {
AC.get('walletPasswordConfirmation').setErrors(null);
return null;
}
}
}
Breeze-1.0.0/Breeze.UI/src/app/shared/pipes/ 0000775 0000000 0000000 00000000000 13334556736 0020430 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/shared/pipes/coin-notation.pipe.spec.ts 0000664 0000000 0000000 00000000324 13334556736 0025445 0 ustar 00root root 0000000 0000000 import { CoinNotationPipe } from './coin-notation.pipe';
describe('CoinNotationPipe', () => {
it('create an instance', () => {
const pipe = new CoinNotationPipe();
expect(pipe).toBeTruthy();
});
});
Breeze-1.0.0/Breeze.UI/src/app/shared/pipes/coin-notation.pipe.ts 0000664 0000000 0000000 00000003571 13334556736 0024523 0 ustar 00root root 0000000 0000000 import { Pipe, PipeTransform } from '@angular/core';
import { GlobalService } from '../services/global.service';
@Pipe({
name: 'coinNotation'
})
export class CoinNotationPipe implements PipeTransform {
constructor (private globalService: GlobalService) {
this.setCoinUnit();
}
private coinUnit: string;
private coinNotation: number;
private decimalLimit = 8;
transform(value: number): number {
let temp;
if (typeof value === 'number') {
switch (this.getCoinUnit()) {
case "BTC":
temp = value / 100000000;
return temp.toFixed(this.decimalLimit);
case "mBTC":
temp = value / 100000;
return temp.toFixed(this.decimalLimit);
case "uBTC":
temp = value / 100;
return temp.toFixed(this.decimalLimit);
case "TBTC":
temp = value / 100000000;
return temp.toFixed(this.decimalLimit);
case "TmBTC":
temp = value / 100000;
return temp.toFixed(this.decimalLimit);
case "TuBTC":
temp = value / 100;
return temp.toFixed(this.decimalLimit);
case "STRAT":
temp = value / 100000000;
return temp.toFixed(this.decimalLimit);
case "mSTRAT":
temp = value / 100000;
return temp.toFixed(this.decimalLimit);
case "uSTRAT":
temp = value / 100;
return temp.toFixed(this.decimalLimit);
case "TSTRAT":
temp = value / 100000000;
return temp.toFixed(this.decimalLimit);
case "TmSTRAT":
temp = value / 100000;
return temp.toFixed(this.decimalLimit);
case "TuSTRAT":
temp = value / 100;
return temp.toFixed(this.decimalLimit);
}
}
}
getCoinUnit() {
return this.coinUnit;
}
setCoinUnit() {
this.coinUnit = this.globalService.getCoinUnit();
};
}
Breeze-1.0.0/Breeze.UI/src/app/shared/services/ 0000775 0000000 0000000 00000000000 13334556736 0021133 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/shared/services/api.service.ts 0000664 0000000 0000000 00000024655 13334556736 0023727 0 ustar 00root root 0000000 0000000 import { Injectable } from '@angular/core';
import { Http, Headers, Response, RequestOptions, URLSearchParams} from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/catch';
import "rxjs/add/observable/interval";
import 'rxjs/add/operator/startWith';
import { GlobalService } from './global.service';
import { WalletCreation } from '../classes/wallet-creation';
import { WalletRecovery } from '../classes/wallet-recovery';
import { WalletLoad } from '../classes/wallet-load';
import { WalletInfo } from '../classes/wallet-info';
import { Mnemonic } from '../classes/mnemonic';
import { FeeEstimation } from '../classes/fee-estimation';
import { TransactionBuilding } from '../classes/transaction-building';
import { TransactionSending } from '../classes/transaction-sending';
/**
* For information on the API specification have a look at our swagger files located at http://localhost:5000/swagger/ when running the daemon
*/
@Injectable()
export class ApiService {
constructor(private http: Http, private globalService: GlobalService) {};
private headers = new Headers({'Content-Type': 'application/json'});
private pollingInterval = 3000;
private bitcoinApiUrl = 'http://localhost:37220/api';
private stratisApiUrl = 'http://localhost:37221/api';
private currentApiUrl = 'http://localhost:37220/api';
private getCurrentCoin() {
let currentCoin = this.globalService.getCoinName();
if (currentCoin === "Bitcoin" || currentCoin === "TestBitcoin") {
this.currentApiUrl = this.bitcoinApiUrl;
} else if (currentCoin === "Stratis" || currentCoin === "TestStratis") {
this.currentApiUrl = this.stratisApiUrl;
}
}
/**
* Gets available wallets at the default path
*/
getWalletFiles(): Observable {
return this.http
.get(this.bitcoinApiUrl + '/wallet/files')
.map((response: Response) => response);
}
/**
* Gets available wallets at the default path
*/
getStratisWalletFiles(): Observable {
return this.http
.get(this.stratisApiUrl + '/wallet/files')
.map((response: Response) => response);
}
/**
* Get a new mnemonic
*/
getNewMnemonic(): Observable {
let params: URLSearchParams = new URLSearchParams();
params.set('language', 'English');
params.set('wordCount', '12');
return this.http
.get(this.bitcoinApiUrl + '/wallet/mnemonic', new RequestOptions({headers: this.headers, search: params}))
.map((response: Response) => response);
}
/**
* Create a new Bitcoin wallet.
*/
createBitcoinWallet(data: WalletCreation): Observable {
return this.http
.post(this.bitcoinApiUrl + '/wallet/create/', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
/**
* Create a new Stratis wallet.
*/
createStratisWallet(data: WalletCreation): Observable {
return this.http
.post(this.stratisApiUrl + '/wallet/create/', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
/**
* Recover a Bitcoin wallet.
*/
recoverBitcoinWallet(data: WalletRecovery): Observable {
return this.http
.post(this.bitcoinApiUrl + '/wallet/recover/', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
/**
* Recover a Stratis wallet.
*/
recoverStratisWallet(data: WalletRecovery): Observable {
return this.http
.post(this.stratisApiUrl + '/wallet/recover/', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
/**
* Load a Bitcoin wallet
*/
loadBitcoinWallet(data: WalletLoad): Observable {
return this.http
.post(this.bitcoinApiUrl + '/wallet/load/', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
/**
* Load a Stratis wallet
*/
loadStratisWallet(data: WalletLoad): Observable {
return this.http
.post(this.stratisApiUrl + '/wallet/load/', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
/**
* Get wallet status info from the API.
*/
getWalletStatus(): Observable {
this.getCurrentCoin();
return this.http
.get(this.currentApiUrl + '/wallet/status')
.map((response: Response) => response);
}
/**
* Get general wallet info from the API once.
*/
getGeneralInfoOnce(data: WalletInfo): Observable {
let params: URLSearchParams = new URLSearchParams();
params.set('Name', data.walletName);
return this.http
.get(this.bitcoinApiUrl + '/wallet/general-info', new RequestOptions({headers: this.headers, search: params}))
.map((response: Response) => response);
}
/**
* Get general wallet info from the API.
*/
getGeneralInfo(data: WalletInfo): Observable {
this.getCurrentCoin();
let params: URLSearchParams = new URLSearchParams();
params.set('Name', data.walletName);
return Observable
.interval(this.pollingInterval)
.startWith(0)
.switchMap(() => this.http.get(this.currentApiUrl + '/wallet/general-info', new RequestOptions({headers: this.headers, search: params})))
.map((response: Response) => response);
}
/**
* Get wallet balance info from the API.
*/
getWalletBalance(data: WalletInfo): Observable {
this.getCurrentCoin();
let params: URLSearchParams = new URLSearchParams();
params.set('walletName', data.walletName);
return Observable
.interval(this.pollingInterval)
.startWith(0)
.switchMap(() => this.http.get(this.currentApiUrl + '/wallet/balance', new RequestOptions({headers: this.headers, search: params})))
.map((response: Response) => response);
}
/**
* Get the maximum sendable amount for a given fee from the API
*/
getMaximumBalance(data): Observable {
this.getCurrentCoin();
let params: URLSearchParams = new URLSearchParams();
params.set('walletName', data.walletName);
params.set('accountName', "account 0");
params.set('feeType', data.feeType);
params.set('allowUnconfirmed', "true");
return this.http
.get(this.currentApiUrl + '/wallet/maxbalance', new RequestOptions({headers: this.headers, search: params}))
.map((response: Response) => response);
}
/**
* Get a wallets transaction history info from the API.
*/
getWalletHistory(data: WalletInfo): Observable {
this.getCurrentCoin();
let params: URLSearchParams = new URLSearchParams();
params.set('walletName', data.walletName);
return Observable
.interval(this.pollingInterval)
.startWith(0)
.switchMap(() => this.http.get(this.currentApiUrl + '/wallet/history', new RequestOptions({headers: this.headers, search: params})))
.map((response: Response) => response);
}
/**
* Get an unused receive address for a certain wallet from the API.
*/
getUnusedReceiveAddress(data: WalletInfo): Observable {
this.getCurrentCoin();
let params: URLSearchParams = new URLSearchParams();
params.set('walletName', data.walletName);
params.set('accountName', "account 0"); //temporary
return this.http
.get(this.currentApiUrl + '/wallet/unusedaddress', new RequestOptions({headers: this.headers, search: params}))
.map((response: Response) => response);
}
/**
* Get multiple unused receive addresses for a certain wallet from the API.
*/
getUnusedReceiveAddresses(data: WalletInfo, count: string): Observable {
this.getCurrentCoin();
let params: URLSearchParams = new URLSearchParams();
params.set('walletName', data.walletName);
params.set('accountName', "account 0"); //temporary
params.set('count', count);
return this.http
.get(this.currentApiUrl + '/wallet/unusedaddresses', new RequestOptions({headers: this.headers, search: params}))
.map((response: Response) => response);
}
/**
* Get get all receive addresses for an account of a wallet from the API.
*/
getAllReceiveAddresses(data: WalletInfo): Observable {
this.getCurrentCoin();
let params: URLSearchParams = new URLSearchParams();
params.set('walletName', data.walletName);
params.set('accountName', "account 0"); //temporary
return this.http
.get(this.currentApiUrl + '/wallet/addresses', new RequestOptions({headers: this.headers, search: params}))
.map((response: Response) => response);
}
/**
* Estimate the fee of a transaction
*/
estimateFee(data: FeeEstimation): Observable {
this.getCurrentCoin();
let params: URLSearchParams = new URLSearchParams();
params.set('walletName', data.walletName);
params.set('accountName', data.accountName);
params.set('destinationAddress', data.destinationAddress);
params.set('amount', data.amount);
params.set('feeType', data.feeType);
params.set('allowUnconfirmed', "true");
return this.http
.get(this.currentApiUrl + '/wallet/estimate-txfee', new RequestOptions({headers: this.headers, search: params}))
.map((response: Response) => response);
}
/**
* Build a transaction
*/
buildTransaction(data: TransactionBuilding): Observable {
this.getCurrentCoin();
return this.http
.post(this.currentApiUrl + '/wallet/build-transaction', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
/**
* Send transaction
*/
sendTransaction(data: TransactionSending): Observable {
this.getCurrentCoin();
return this.http
.post(this.currentApiUrl + '/wallet/send-transaction', JSON.stringify(data), {headers: this.headers})
.map((response: Response) => response);
}
/**
* Send shutdown signal to the daemon
*/
shutdownNode(): Observable {
this.getCurrentCoin();
return this.http
.post(this.currentApiUrl + '/node/shutdown', '')
.map((response: Response) => response);
}
}
Breeze-1.0.0/Breeze.UI/src/app/shared/services/global.service.ts 0000664 0000000 0000000 00000002021 13334556736 0024375 0 ustar 00root root 0000000 0000000 import {Injectable} from "@angular/core";
@Injectable()
export class GlobalService {
constructor() {}
private walletPath: string;
private currentWalletName: string;
private coinType: number;
private coinName: string;
private coinUnit: string;
private network: string;
getWalletPath() {
return this.walletPath;
}
setWalletPath(walletPath: string) {
this.walletPath = walletPath;
}
getNetwork() {
return this.network;
}
setNetwork(network: string) {
this.network = network;
}
getWalletName() {
return this.currentWalletName;
}
setWalletName(currentWalletName: string) {
this.currentWalletName = currentWalletName;
}
getCoinType() {
return this.coinType;
}
setCoinType (coinType: number) {
this.coinType = coinType;
}
getCoinName() {
return this.coinName;
}
setCoinName(coinName: string) {
this.coinName = coinName;
}
getCoinUnit() {
return this.coinUnit;
}
setCoinUnit(coinUnit: string) {
this.coinUnit = coinUnit;
}
}
Breeze-1.0.0/Breeze.UI/src/app/shared/services/modal.service.ts 0000664 0000000 0000000 00000001044 13334556736 0024235 0 ustar 00root root 0000000 0000000 import {Injectable} from "@angular/core";
import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { GenericModalComponent } from '../components/generic-modal/generic-modal.component';
@Injectable()
export class ModalService {
constructor(private modalService: NgbModal) {}
public openModal(title, body) {
const modalRef = this.modalService.open(GenericModalComponent)
if (title) {
modalRef.componentInstance.title = title;
}
if (body) {
modalRef.componentInstance.body = body;
}
}
}
Breeze-1.0.0/Breeze.UI/src/app/shared/services/navigation.service.ts 0000664 0000000 0000000 00000001467 13334556736 0025311 0 ustar 00root root 0000000 0000000 import { Injectable } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { ReplaySubject } from 'rxjs/ReplaySubject';
export enum Page {
Bitcoin, Stratis
}
@Injectable()
export class NavigationService {
private readonly navBase = '/wallet';
constructor(router: Router) {
const navigation$ = router.events.filter(x => x instanceof NavigationEnd)
.map(x => x)
.map(x => x.url);
navigation$.filter(x => x === this.navBase).subscribe(_ => this.pageSubject.next(Page.Bitcoin));
navigation$.filter(x => x === `${this.navBase}/stratis-wallet`).subscribe(_ => this.pageSubject.next(Page.Stratis));
}
public pageSubject = new ReplaySubject(1);
}
Breeze-1.0.0/Breeze.UI/src/app/shared/shared.module.ts 0000664 0000000 0000000 00000001225 13334556736 0022412 0 ustar 00root root 0000000 0000000 import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CoinNotationPipe } from './pipes/coin-notation.pipe';
import { AutoFocusDirective } from './directives/auto-focus.directive';
import { PasswordValidationDirective } from './directives/password-validation.directive';
@NgModule({
imports: [CommonModule],
declarations: [CoinNotationPipe, AutoFocusDirective, PasswordValidationDirective],
exports: [CoinNotationPipe, AutoFocusDirective]
})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: SharedModule,
providers: []
};
}
}
Breeze-1.0.0/Breeze.UI/src/app/wallet/ 0000775 0000000 0000000 00000000000 13334556736 0017332 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/wallet/advanced/ 0000775 0000000 0000000 00000000000 13334556736 0021077 5 ustar 00root root 0000000 0000000 Breeze-1.0.0/Breeze.UI/src/app/wallet/advanced/advanced.component.css 0000664 0000000 0000000 00000000250 13334556736 0025354 0 ustar 00root root 0000000 0000000 .mainDiv {
margin-left: 100px;
margin-top: 20px;
}
::ng-deep ng-datepicker input {
height: 35px;
}
.label {
font-size: 14px;
margin-bottom: 1px;
} Breeze-1.0.0/Breeze.UI/src/app/wallet/advanced/advanced.component.html 0000664 0000000 0000000 00000005326 13334556736 0025541 0 ustar 00root root 0000000 0000000