├── .gitignore
├── LICENSE
├── README.md
├── account_info.js
├── check_stash.js
├── delete.js
├── new.js
├── newQR.js
├── newQRimg.jpg
├── package.json
├── secret2address.js
├── secret2addressQR.js
├── server_info.js
├── showQR.js
├── sign.js
├── signQR.js
├── submit.js
├── warp2account.js
├── warp2accountQR.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Duke67
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # xrptoolkit-nodejs
2 |
3 | A toolkit for safe and secure access to XRP ledger (Ripple Network).
4 |
5 | If used properly, these tools allow you to actively use your XRP assets, while keeping the highest possible level of safety and security
6 |
7 |
8 | # Features
9 | - Follows and leverages Ripple’s Reliable Transaction Submission
10 | - Allows you to keep sensitive info (Ripple Secret) always offline and thus secure
11 | - Maintains the air-gap between online and offline devices
12 | - Connected device can only see encrypted data
13 | - QR codes and OCR makes data transfers quick and convenient
14 | - Avoids using USB devices
15 | - Clean and compact code allows inspection by end-user, 3rd party or community
16 |
17 |
18 | # Functionality
19 | - Access to XRP ledger from:
20 | - Node.js (Linux, MacOS, Windows)
21 | - Android client (xrptoolkit-android)
22 | - iOS client (xrptoolkit-ios - planned)
23 | - Monitors XRP ledger (ledger, accounts, balances, etc.)
24 | - Securely creates new accounts (offline)
25 | - Securely signs payments (offline)
26 | - Submits offline-signed transactions to XRP ledger
27 | - Extracts Ripple address (public) from Ripple secret (private)
28 | - Shows Ripple address as a QR code
29 | - NEW: AccountDelete
30 |
31 |
32 | # Getting started
33 | First try to familiarize yourself with how Ripple network works:
34 | - [Ripple Developer Center](https://ripple.com/build/)
35 | - [Ripple API Beginners Guide](https://ripple.com/build/rippleapi-beginners-guide/)
36 | - [Reliable Transaction Submission](https://ripple.com/build/reliable-transaction-submission/)
37 |
38 |
39 | # Installation (Online computer)
40 |
41 | Install Dependencies
42 |
43 | Install Node.js, if you haven't already. In the following steps, either `yarn` or `npm` can be used, but `yarn` is preferred for the extra reliability.
44 |
45 | Clone the xrptoolkit-nodejs repository and install dependencies
46 |
47 | ```
48 | $ git clone https://github.com/Duke67/xrptoolkit-nodejs xrptoolkit
49 | $ cd xrptoolkit
50 | $ yarn install
51 | ```
52 |
53 | Test your installation:
54 |
55 | ```
56 | $ node new
57 | ```
58 |
59 | You should see something like this:
60 |
61 | ```
62 | user@host:~/xrptoolkit$ node new
63 | Ripple Account : ryH1ckEKUm4yeLTziToAltWYtsrYSV4Po
64 | Ripple Secret : ss467Gz1g5YikcCxHePFShkoZBPzr
65 | user@host:~/xrptoolkit$
66 | ```
67 |
68 | Now test the QR version of the script to check if internal web server and QR code generation works:
69 |
70 | ```
71 | $ node newQR
72 | ```
73 |
74 | Now your web browser should open and display something like this:
75 |
76 | 
77 |
78 |
79 | # Installation (Offline computer)
80 | - Make a fresh Linux installation (Ubuntu 16+ or similar)
81 | - Copy here complete “xrptoolkit-nodejs” folder including its subfolders from the online computer
82 | - Never connect this computer to the Internet (i.e. disable WiFi in BIOS, or switch network button off)
83 |
84 |
85 | # Configurations
86 | - Linux (online) – Linux (offline)
87 | - Android (online) – Linux (offline)
88 | - Linux (online)
89 |
90 |
91 | # Usage
92 |
93 |
94 | ### Create New Account
95 | ```
96 | $ node new
97 | ```
98 | - You will see Ripple Account and Secret in console (terminal)
99 | - Save to a secure location for future use
100 | - Hint: Do some work before this, to give the OS a chance to collect some entropy. Never create accounts immediately after the system boots up!
101 |
102 |
103 |
104 | ### Create New Account (QR code)
105 | ```
106 | $ node newQR
107 | ```
108 | - You will see Ripple Account and Secret in web browser
109 | - Save text and QRcode images to a secure location for future use
110 | - Hint: Do some work before this, to give the OS a chance to collect some entropy. Never create accounts immediately after the system boots up!
111 |
112 |
113 |
114 | ### Check Account Information
115 | ```
116 | $ node account_info [RCL|TEST] account
117 | ```
118 | - Use RCL or TEST parameter to select production or test network
119 | - You will see account’s Balance (in XRP, not drops) and Sequence in console
120 |
121 | ```
122 | $ node account_info RCL rAAAAAAAAAAAAAAAAAAAAAAACNT
123 | Balance : 22500
124 | Sequence: 7
125 | ```
126 |
127 |
128 | ### Check Server Information
129 | ```
130 | $ node server_info [RCL|TEST]
131 | ```
132 | - Use RCL or TEST parameter to select production or test network
133 | - You will see a complex JSON-formatted server information
134 | - Hint: parameter "ledgerVersion" in section "validatedLedger" is used when signing offline transactions
135 |
136 |
137 | ### Check Stash
138 | ```
139 | $ node check_stash
140 | ```
141 | - Use text editor to preset array of variables with your accounts list
142 | - You will see accounts complete balances, including non-XRP assets
143 |
144 |
145 | ### Sign Payment
146 | ```
147 | $ node sign SRC SECRET SEQ DST DSTTAG AMOUNT MAXLEDGER
148 | ```
149 | - Before signing payment offline, you will need to know:
150 | - source account
151 | - source account’s secret
152 | - source sequence (use Android client, or account_info)
153 | - destination address
154 | - destination tag (can be ignored, if not required by receipient)
155 | - maximum ledger (use Android client, or server_info and adjust accordingly)-
156 | - Payment amount is in drops (1,000,000 drops = 1 XRP)
157 |
158 | - Hints:
159 | - Use text editor to preset default variables with your own data
160 | - You may want to create custom copies of this script for frequent payments
161 | - New ledger is closed every 3-4 seconds. If you will need 1-2 minutes to submit this payment to live network, better add 20-50 or even more to what is reported by server_info.
162 |
163 | - You will see JSON-formatted payment details and then signed transaction’s text blob
164 | - Transfer signed transaction to online device (computer or Android client) for submission to Ripple network
165 |
166 | ```
167 | $ node sign raakAtsGGZGGs8xb8AxDEUyWj7UxNGHGb7 shkJ3HM8jcrKvpYAifJhwvkaGDEtm 16
168 | rGNLJ5VLZWKt7RrQrbyUZjXa2mCCcEenpu 1967 25000000 35000000
169 |
170 | {"TransactionType":"Payment","Account":"raakAtsGGZGGs8xb8AxDEUyWj7UxNGHGb7",
171 | "Destination":"rGNLJ5VLZWKt7RrQrbyUZjXa2mCCcEenpu","DestinationTag":"1967","Amount":"25000000",
172 | "Flags":2147483648,"LastLedgerSequence":35000000,"Fee":"12","Sequence":16}
173 |
174 | SIGNED TX:
175 |
176 | 120000228000000024000000102E000007AF201B02160EC06140000000017D784068400000000000000C7321022CC705F
177 | 4FEE39CEFE883FE86853EF866EF26764AC31362AAD37E6573F8CFE9E074473045022100D2D6A554D11E55290F216A8FB9
178 | CC2921A498DC4FF357D480589F72550810A7CC02202BBB48C1342631BA514A307AF523C77CBD4406D19CEC69F0508187A
179 | 7BD7265F7811437EF64A707F99867C5E2B8DB5E902D9CD04158D28314A70F68DD4D41D95468A8E61BC32DE25862F63CA6
180 |
181 | $
182 | ```
183 |
184 |
185 | ### Sign Payment (QR code)
186 | ```
187 | $ node signQR SRC SECRET SEQ DST DSTTAG AMOUNT MAXLEDGER
188 | ```
189 | - Before signing payment offline, you will need to know:
190 | - source account
191 | - source account’s secret
192 | - source sequence (use Android client, or account_info)
193 | - destination address
194 | - destination tag (can be ignored, if not required by receipient)
195 | - maximum ledger (use Android client, or server_info and adjust accordingly)
196 | - Payment amount is in drops (1,000,000 drops = 1 XRP)
197 |
198 | - Hints:
199 | - Use text editor to preset default variables with your own data
200 | - You may want to create custom copies of this script for frequent payments
201 | - New ledger is closed every 3-4 seconds. If you will need 1-2 minutes to submit this payment to live network, better add 20-50 or even more to what is reported by server_info.
202 |
203 | - In a web browser you will see QR code and text blob representing signed transaction
204 | - Use Android client QR feature to scan and instantly submit transaction to Ripple network
205 |
206 |
207 | ### Submit
208 | ```
209 | $ node submit [RCL|TEST] SIGNED_TX
210 | ```
211 | - Use RCL or TEST parameter to select production or test network
212 | - Use sign or signQR to generate SIGNED_TX text blob
213 | - After a submission you will see a preliminary information on status
214 | - Final information about validation by the network can be obtained by monitoring the account or the transation
215 |
216 | ### Secret2address
217 | ```
218 | $ node secret2address [SECRET]
219 | ```
220 | - Extracts Ripple address (public) from Ripple secret (private)
221 | - If no secret is provided, it creates a new address
222 |
223 |
224 | ### Secret2addressQR
225 | ```
226 | $ node secret2addressQR [SECRET]
227 | ```
228 | - Extracts Ripple address (public) from Ripple secret (private)
229 | - Displays all data including QR codes in a web browser
230 | - If no secret is provided, it creates a new address
231 |
232 | ### Warp2account
233 | ```
234 | $ node warp2account [PASSWORD] [SALT]
235 | ```
236 | - Extracts Ripple address (public) and Ripple secret (private) from RippleWarpWallet Password and Salt
237 |
238 | ### Warp2accountQR
239 | ```
240 | $ node warp2accountQR [PASSWORD] [SALT]
241 | ```
242 | - Extracts Ripple address (public) and Ripple secret (private) from RippleWarpWallet Password and Salt
243 | - Displays all data including QR codes in a web browser
244 |
245 | ### ShowQR
246 | ```
247 | $ node showQR [ACCOUNT|SECRET]
248 | ```
249 | - Generates a QR code for a text provided
250 | - Display it in a web browser
251 |
252 |
253 | # Future development
254 | - Support for other crypto currencies, fiat and IOUs
255 | - Escrow
256 | - Multi-sign
257 | - iOS client for Apple iPhone
258 |
259 | # Release notes
260 | - 1.0.0 - initial release
261 | - 1.0.1 - improved web browser launching (QR scripts versions)
262 |
263 | # Contact
264 | - Follow [@MrDuke67 on twitter](https://twitter.com/MrDuke67)
265 |
266 |
267 | # License
268 | - (https://github.com/Duke67/xrptoolkit-nodejs/blob/master/LICENSE)
269 |
--------------------------------------------------------------------------------
/account_info.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // account_info.js - displays account's basic info
8 | // syntax: node account_info [RCL|TEST] ACCOUNT
9 | //
10 | // HINT - see Sequence to determine source account's
11 | // sequence, when signing payment offline
12 | //
13 | ///////////////////////////////////////////////////////////
14 |
15 | 'use strict';
16 | const RippleAPI = require('ripple-lib').RippleAPI;
17 |
18 | ///////////////////////////////////////////////////////////
19 |
20 | var api;
21 | var net = process.argv[2];
22 |
23 | if (net == 'TEST') {
24 | api = new RippleAPI({ server: 'wss://s.altnet.rippletest.net:51233' });
25 | } else {
26 | api = new RippleAPI({ server: 'wss://s1.ripple.com:443' });
27 | }
28 |
29 | ///////////////////////////////////////////////////////////
30 |
31 | var acnt = process.argv[3];
32 |
33 | console.log('XRPtk-nodejs: account_info ' + acnt);
34 |
35 | ///////////////////////////////////////////////////////////
36 |
37 | api.on('connected', () => {
38 | process.exitCode = 1;
39 | console.log('connected');
40 | });
41 | api.on('disconnected', (code) => {
42 | console.log('disconnected, code:', code);
43 | });
44 | api.on('error', (errorCode, errorMessage) => {
45 | console.log(errorCode + ': ' + errorMessage);
46 | });
47 |
48 | ///////////////////////////////////////////////////////////
49 |
50 | function getAccount(address){
51 | return api.getAccountInfo(address).then(info => {
52 | //balance = info.xrpBalance;
53 | //console.log(info.xrpBalance);
54 | return info;
55 | });
56 | }
57 |
58 | ///////////////////////////////////////////////////////////
59 |
60 | api.connect().then(() => {
61 |
62 | return getAccount(acnt);
63 |
64 | }).then(info => {
65 |
66 | console.log("Balance : " + info.xrpBalance);
67 | console.log("Sequence: " + info.sequence);
68 |
69 | }).then(() => {
70 |
71 | return api.disconnect();
72 |
73 | }).catch(console.error);
74 |
75 | ///////////////////////////////////////////////////////////
76 |
--------------------------------------------------------------------------------
/check_stash.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // check_stash.js - check balance of several Ripple accounts at once
8 | // syntax: node check_stash
9 | //
10 | ///////////////////////////////////////////////////////////
11 |
12 | 'use strict';
13 |
14 | const RippleAPI = require('ripple-lib').RippleAPI;
15 |
16 | const api = new RippleAPI({server: 'wss://s1.ripple.com:443'});
17 | //const api = new RippleAPI({ server: 'wss://s.altnet.rippletest.net:51233' });
18 |
19 |
20 | ///
21 | /// HINT - use text editor to preset the following array with your data
22 | ///
23 |
24 | var accounts = [
25 | 'rhT2zX6SqTycCnGfGLKBBjVnvWmuyGFb7A',
26 | 'radkxo6zoVUyYt2NfRFSnELWnxbHUuuyBp',
27 | 'r9ZWnxoJajbnyL1W73uYkQbztrwf3qRBTt'
28 | ];
29 |
30 | ///
31 |
32 | api.on('connected', () => {
33 | console.log('connected');
34 | });
35 | api.on('disconnected', (code) => {
36 | console.log('disconnected, code:', code);
37 | });
38 | api.on('error', (errorCode, errorMessage) => {
39 | console.log(errorCode + ': ' + errorMessage);
40 | });
41 |
42 | ///
43 |
44 | api.connect().then(() => {
45 |
46 | console.log('Account queried...');
47 |
48 | for (var i = 0; i < accounts.length; i++) {
49 |
50 | var acnt = accounts[i];
51 | console.log('Account : ' + acnt);
52 |
53 | api.getBalances(acnt).then(balances => {
54 | console.log(JSON.stringify(balances, null, 2));
55 | });
56 |
57 | }
58 |
59 | }).then(() => {
60 |
61 | console.log('Balance is coming now...');
62 |
63 | }).then(() => {
64 |
65 | api.disconnect();
66 |
67 | }).catch(console.error);
68 |
69 | ///////////////////////////////////////////////////////////
70 |
71 |
--------------------------------------------------------------------------------
/delete.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2020 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // delete.js - delete XRP account
8 | // syntax: node delete [XRPL|TEST] ACCOUNT SECRET SEQ DST DSTTAG
9 | //
10 | ///////////////////////////////////////////////////////////
11 |
12 | 'use strict';
13 |
14 | const RippleAPI = require('ripple-lib').RippleAPI;
15 |
16 | var api;
17 | var net = process.argv[2];
18 |
19 |
20 | if (net == 'TEST') {
21 | api = new RippleAPI({ server: 'wss://s.altnet.rippletest.net:51233', maxFeeXRP: '5' });
22 | } else {
23 | api = new RippleAPI({ server: 'wss://s1.ripple.com:443', maxFeeXRP: '5' });
24 | }
25 |
26 |
27 |
28 | ///
29 | /// HINT
30 | /// 1. use editor to preset the following variables with your data
31 | /// 2. create custom copies of this script for frequent payments
32 | ///
33 |
34 | var src = 'rHqaHPMmdWWSv2EmXGDwXmtgnC5hXR5zUy'; // account to be deleted
35 | var dst = 'r4qSyg6j77me6seoBEDKXF3tueFiZtP5t2'; // destination account
36 | var tag = '123'; // destination tag
37 | var scrt = 'spvdQ8sHG6wCP7K7nGHGUpe4LLFkq'; // source account's secret
38 |
39 | var seq = 1; // source account's sequence (to get this info, use XRPtoolkit-Android or account_info.js)
40 | var fee = 5000000; // fee (default is 5 XRPs (5000000 drops)
41 |
42 | ///
43 |
44 | process.argv.forEach(function (val, index, array) {
45 |
46 | console.log(index + ': ' + val);
47 |
48 | switch(index) {
49 | case 2:net = val;break;
50 | case 3:src = val;break;
51 | case 4:scrt = val;break;
52 | case 5:seq = val;break;
53 | case 6:dst = val;break;
54 | case 7:tag = val;break;
55 | default:break;
56 | }
57 |
58 | });
59 |
60 | ///////////////////////////////////////////////////////////
61 |
62 | var rawTx = '{"TransactionType":"AccountDelete",' +
63 | '"Account":"' + src +
64 | '","Destination":"' + dst +
65 | '","DestinationTag":' + tag +
66 | ',"Fee":"' + fee +
67 | '","Sequence":' + seq +
68 | ',"Flags":2147483648' +
69 | '}';
70 |
71 | ///////////////////////////////////////////////////////////
72 |
73 | console.log();
74 | console.log(rawTx);
75 |
76 | api.connect().then(() => {
77 |
78 | console.log('WORKING:');
79 |
80 | var sgnd = api.sign(rawTx, scrt).signedTransaction;
81 | console.log(sgnd);
82 |
83 | api.submit(sgnd).then( response => {
84 | console.log('RESPONSE:');
85 | console.log(response.resultCode, response.resultMessage);
86 | }).catch(console.error)
87 |
88 | }).then(() => {
89 |
90 | console.log('AccountDelete is being processed by XRPL...');
91 |
92 | }).then(() => {
93 |
94 | api.disconnect();
95 |
96 | }).catch(console.error);
97 |
98 | console.log();
99 |
100 | ///////////////////////////////////////////////////////////
101 |
102 |
--------------------------------------------------------------------------------
/new.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // new_simple.js - creates new Ripple account
8 | // syntax: node new_simple
9 | //
10 | ///////////////////////////////////////////////////////////
11 |
12 | 'use strict';
13 |
14 | const RippleAPI = require('ripple-lib').RippleAPI;
15 |
16 | var api = new RippleAPI();
17 |
18 | ///////////////////////////////////////////////////////////
19 |
20 | // generate new Ripple Account
21 | var ra = api.generateAddress();
22 | var acnt = ra.address.toString();
23 | var scrt = ra.secret.toString();
24 |
25 | console.log('Ripple Account : ' + acnt);
26 | console.log('Ripple Secret : ' + scrt);
27 |
28 | ///////////////////////////////////////////////////////////
29 |
--------------------------------------------------------------------------------
/newQR.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // new.js - creates new Ripple account and shows its QR codes
8 | // syntax: node new
9 | //
10 | ///////////////////////////////////////////////////////////
11 |
12 | 'use strict';
13 |
14 | const RippleAPI = require('ripple-lib').RippleAPI;
15 |
16 | var express = require('express');
17 | var qrcode = require('qrcode');
18 | var launcher = require('launch-browser');
19 |
20 | var api = new RippleAPI();
21 |
22 | ///////////////////////////////////////////////////////////
23 |
24 | var app = express();
25 |
26 | app.get('/', function(req, res) {
27 |
28 | res.writeHead(200, { 'Content-Type': 'text/html' });
29 |
30 | // generate new Ripple Account
31 | var ra = api.generateAddress();
32 | var acnt = ra.address.toString();
33 | var scrt = ra.secret.toString();
34 |
35 | //console.log('Ripple Account : ' + acnt);
36 | //console.log('Ripple Secret : go to http://localhost:3000/ and click "Reveal" button');
37 |
38 |
39 | // display it in a web browser
40 | var html = "";
41 | html += "
XRPtoolkit by Duke67";
42 | html += "";
43 |
44 | html += "
XRPtoolkit by Duke67
";
45 | html += "
New Ripple Account has been generated
";
46 |
47 | var opts = {
48 | errorCorrectionLevel: 'H',
49 | type: 'image/png',
50 | scale: 10
51 | };
52 |
53 | // generate QR code of Ripple Address (public)
54 | qrcode.toDataURL(acnt, opts, function (err, url1) {
55 |
56 | // display it in the web browser
57 | html += "
";
58 | html += "Ripple Account:
";
59 | html += acnt + " ";
60 | html += " ";
61 | html += "
";
62 | });
63 |
64 | // generate QR code of Ripple Secret (private)
65 | opts.color.dark = '#F00'; // show Ripple secret in RED
66 | opts.scale = 5; // make Ripple secret SMALLER than account
67 | qrcode.toDataURL(scrt, opts, function (err2, url2) {
68 |
69 | // display it in the web browser
70 | html += "
";
71 | html += "Ripple Secret:
";
72 |
73 | // include script to display Ripple Secret (initially hidden for security purposes)
74 | html += ""
77 |
78 | // Reveal button
79 | html += "";
80 |
81 | html += "
";
82 | html += scrt + " ";
83 | html += " ";
84 | html += "
";
85 |
86 | html += "
";
87 | html += "";
88 |
89 | res.end(html);
90 | });
91 |
92 |
93 |
94 | });
95 |
96 | //console.log('To see the QR code, point your web browser to http://localhost:3000/');
97 | console.log('Press Ctrl+C to quit this script.');
98 |
99 | app.listen(3000);
100 |
101 | launcher('http://localhost:3000/', { browser: ['chrome', 'firefox', 'safari'] }, function(e, browser){
102 | if(e) return console.log(e);
103 | });
104 |
105 | ///////////////////////////////////////////////////////////
106 |
107 |
--------------------------------------------------------------------------------
/newQRimg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Duke67/xrptoolkit-nodejs/fae7e21194247ffc3c5c130be492010fa7676066/newQRimg.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xrptoolkit",
3 | "version": "2.0.0",
4 | "description": "A toolkit for safe and secure access to the XRP ledger (Ripple Network)",
5 | "main": "new.js",
6 | "repository": "https://github.com/Duke67/xprtoolkit-nodejs",
7 | "author": "Duke67",
8 | "license": "MIT",
9 | "dependencies": {
10 | "express": "^4.16.2",
11 | "launch-browser": "^1.0.0",
12 | "progress": "^2.0.0",
13 | "qrcode": "^1.2.0",
14 | "ripple-lib": "*"
15 | },
16 | "devDependencies": {
17 | "eslint": "*"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/secret2address.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // secret2address.js - extracts full Ripple address from secret
8 | // syntax: node secret2address [SECRET]
9 | //
10 | // HINT - if not secret is provided, it generates new Ripple account
11 | //
12 | ///////////////////////////////////////////////////////////
13 |
14 | 'use strict';
15 |
16 | var keypairs = require('ripple-keypairs');
17 |
18 | var scrt = (process.argv.length > 2) ? process.argv[2] : keypairs.generateSeed();
19 |
20 | var pair = keypairs.deriveKeypair(scrt);
21 | var acnt = keypairs.deriveAddress(pair.publicKey)
22 |
23 | console.log('Ripple Account : ' + acnt);
24 | console.log('Ripple Secret : ' + scrt);
25 |
26 | ///////////////////////////////////////////////////////////
27 |
28 |
--------------------------------------------------------------------------------
/secret2addressQR.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // secret2addressQR.js - extracts full Ripple address from secret
8 | // syntax: node secret2addressQR [SECRET]
9 | //
10 | // HINT - if not secret is provided, it generates new Ripple account
11 | //
12 | ///////////////////////////////////////////////////////////
13 |
14 | 'use strict';
15 |
16 | var express = require('express');
17 | var qrcode = require('qrcode');
18 | var launcher = require('launch-browser');
19 |
20 | var keypairs = require('ripple-keypairs');
21 |
22 | var scrt = (process.argv.length > 2) ? process.argv[2] : keypairs.generateSeed();
23 |
24 | ///////////////////////////////////////////////////////////
25 |
26 | var app = express();
27 |
28 | app.get('/', function(req, res) {
29 |
30 | res.writeHead(200, { 'Content-Type': 'text/html' });
31 |
32 | // derive full Ripple address
33 | var pair = keypairs.deriveKeypair(scrt);
34 | var acnt = keypairs.deriveAddress(pair.publicKey)
35 |
36 | // display it in a web browser
37 | var html = "";
38 | html += "XRPtoolkit by Duke67";
39 | html += "";
40 |
41 | html += "
XRPtoolkit by Duke67
";
42 | html += "
Ripple Account was extracted from Secret
";
43 |
44 | var opts = {
45 | errorCorrectionLevel: 'H',
46 | type: 'image/png',
47 | scale: 10
48 | };
49 |
50 | // generate QR code of Ripple Address (public)
51 | qrcode.toDataURL(acnt, opts, function (err, url1) {
52 |
53 | // display it in the web browser
54 | html += "
";
55 | html += "Ripple Account:
";
56 | html += acnt + " ";
57 | html += " ";
58 | html += "
";
59 | });
60 |
61 | // generate QR code of Ripple Secret (private)
62 | opts.color.dark = '#F00'; // show Ripple secret in RED
63 | opts.scale = 5; // make Ripple secret SMALLER than account
64 | qrcode.toDataURL(scrt, opts, function (err2, url2) {
65 |
66 | // display it in the web browser
67 | html += "
";
68 | html += "Ripple Secret:
";
69 |
70 | // include script to display Ripple Secret (initially hidden for security purposes)
71 | html += ""
74 |
75 | // Reveal button
76 | html += "";
77 |
78 | html += "
";
79 | html += scrt + " ";
80 | html += " ";
81 | html += "
";
134 | html += "Signed Transaction ";
135 | html += "
";
136 |
137 | html += "
";
138 | html += "QR code: ";
139 | html += " ";
140 | html += "
";
141 |
142 | html += "
";
143 | html += "Blob:
";
144 | html += "";
145 | html += signedTx.signedTransaction;
146 | html += "";
147 | html += "
";
148 |
149 | html += "";
150 |
151 | res.end(html);
152 | });
153 |
154 |
155 | });
156 |
157 | app.listen(3000);
158 |
159 | launcher('http://localhost:3000/', { browser: ['chrome', 'firefox', 'safari'] }, function(e, browser){
160 | if(e) return console.log(e);
161 | });
162 |
163 | ///////////////////////////////////////////////////////////
164 |
165 |
--------------------------------------------------------------------------------
/submit.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // submit.js - submits signed transaction to Ripple network
8 | // syntax: node submit [RCL|TEST] SIGNED_TX
9 | //
10 | ///////////////////////////////////////////////////////////
11 |
12 | 'use strict';
13 |
14 | const RippleAPI = require('ripple-lib').RippleAPI;
15 |
16 | ///////////////////////////////////////////////////////////
17 |
18 | var api;
19 | var net = process.argv[2];
20 | var signedTx = 'NULL';
21 |
22 | if (net == 'TEST') {
23 | api = new RippleAPI({ server: 'wss://s.altnet.rippletest.net:51233' });
24 | } else {
25 | api = new RippleAPI({ server: 'wss://s1.ripple.com:443' });
26 | }
27 |
28 | ///////////////////////////////////////////////////////////
29 |
30 | signedTx = process.argv[3];
31 |
32 | console.log('XRPtk-nodejs: submit ' + signedTx);
33 |
34 | ///////////////////////////////////////////////////////////
35 |
36 | api.on('connected', () => {
37 | process.exitCode = 1;
38 | console.log('connected');
39 | });
40 | api.on('disconnected', (code) => {
41 | console.log('disconnected, code:', code);
42 | });
43 | api.on('error', (errorCode, errorMessage) => {
44 | console.log(errorCode + ': ' + errorMessage);
45 | });
46 |
47 | ///////////////////////////////////////////////////////////
48 |
49 | function quit(message) {
50 | return api.disconnect();
51 | console.log(message);
52 | process.exit(0);
53 | }
54 |
55 | function fail(message) {
56 | return api.disconnect();
57 | console.error(message);
58 | process.exit(1);
59 | }
60 |
61 | ///////////////////////////////////////////////////////////
62 |
63 | api.connect().then(() => {
64 |
65 | api.submit(signedTx).then(quit, fail);
66 |
67 | }).catch(fail);
68 |
69 | ///////////////////////////////////////////////////////////
70 |
--------------------------------------------------------------------------------
/warp2account.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // warp2account.js - extracts ripple account secret and address from
8 | // RippleWarpWallet password and salt.
9 | //
10 | // syntax: node warp2account [PASSWORD] [SALT]
11 | //
12 | // HINT - default salt can be set in the file to make the salt argument optional
13 | //
14 | ///////////////////////////////////////////////////////////
15 |
16 | 'use strict';
17 |
18 | // HINT - Change this to your email address or whatever other salt
19 | // you would like to use so you don't have to type it in to the
20 | // command line every time.
21 | var DEFAULT_SALT = null;
22 |
23 | var warp = require('ripplewarpwallet');
24 | var ProgressBar = require('progress');
25 |
26 |
27 | if (process.argv.length < 3) {
28 | console.log('Must supply warp password and optional salt. ' + (DEFAULT_SALT === null ? '' : 'Default salt is set to: ' + DEFAULT_SALT));
29 | return 0;
30 | } else if (DEFAULT_SALT === null && process.argv.length < 4) {
31 | console.log('!!!WARNING! Proceeding without salt!!!');
32 | }
33 |
34 | var password = process.argv[2];
35 | var salt = DEFAULT_SALT
36 | if (salt === null) {
37 | if (process.argv.length > 3) {
38 | salt = process.argv[3];
39 | } else {
40 | salt = '';
41 | }
42 | console.log('Proceeding with password "' + password + '" and salt "' + salt + '".');
43 | } else {
44 | console.log('Proceeding with password "' + password + '" and default salt "' + salt + '".');
45 | }
46 |
47 | const params = {
48 | passphrase : password,
49 | salt : salt,
50 | progress_hook : logOutput
51 | };
52 |
53 | var startedScrypt = false;
54 | var startedPbkdf2 = false;
55 | var scryptBar;
56 | var pbkdf2Bar;
57 | var lastProgress = 0;
58 | function logOutput(progress) {
59 | if (progress.what === 'scrypt') {
60 | if (startedScrypt) {
61 | scryptBar.tick(progress.i - lastProgress);
62 | lastProgress = progress.i;
63 | if (lastProgress === progress.total) {
64 | lastProgress = 0;
65 | }
66 | } else {
67 | scryptBar = new ProgressBar('Scrypt: [:bar] :percent', {
68 | complete: '#',
69 | incomplete: ' ',
70 | total: 524288
71 | });
72 | startedScrypt = true;
73 | }
74 | }
75 | if (progress.what === 'pbkdf2') {
76 | if (startedPbkdf2) {
77 | pbkdf2Bar.tick(progress.i - lastProgress);
78 | lastProgress = progress.i;
79 | if (lastProgress === progress.total) {
80 | lastProgress = 0;
81 | }
82 | } else {
83 | pbkdf2Bar = new ProgressBar('PBKDF2: [:bar] :percent', {
84 | complete: '#',
85 | incomplete: ' ',
86 | total: 65536
87 | });
88 | startedPbkdf2 = true;
89 | }
90 | }
91 | }
92 |
93 | function done(res) {
94 | console.log('Ripple Address : ' + res.address);
95 | console.log('Ripple Secret : ' + res.secret);
96 | console.log('///// ADVANCED /////');
97 | console.log('Raw Private Key : ' + res.privateKey);
98 | console.log('Raw Public Key : ' + res.publicKey);
99 | }
100 |
101 | warp(params, done);
102 |
103 | ///////////////////////////////////////////////////////////
104 |
105 |
--------------------------------------------------------------------------------
/warp2accountQR.js:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////
2 | //
3 | // Duke67 XRPtoolkit
4 | // (C) 2017 Duke67 (MrDuke67@outlook.com)
5 | // https://github.com/Duke67/xrptoolkit-nodejs
6 | //
7 | // warp2account.js - extracts ripple account secret and address from
8 | // RippleWarpWallet password and salt.
9 | //
10 | // syntax: node warp2account [PASSWORD] [SALT]
11 | //
12 | // HINT - default salt can be set in the file to make the salt argument optional
13 | //
14 | ///////////////////////////////////////////////////////////
15 |
16 | 'use strict';
17 |
18 | // HINT - Change this to your email address or whatever other salt
19 | // you would like to use so you don't have to type it in to the
20 | // command line every time.
21 | var DEFAULT_SALT = null;
22 |
23 | var express = require('express');
24 | var qrcode = require('qrcode');
25 | var launcher = require('launch-browser');
26 | var warp = require('ripplewarpwallet');
27 | var ProgressBar = require('progress');
28 |
29 | if (DEFAULT_SALT === null && process.argv.length < 4) {
30 | console.log('!!!WARNING! Proceeding without salt!!!');
31 | } else if (process.argv.length < 3) {
32 | console.log('Must supply warp password and optional salt. ' + DEFAULT_SALT === null ? '' : 'Default salt is set to: ' + DEFAULT_SALT);
33 | }
34 |
35 | var password = process.argv[2];
36 | var salt = DEFAULT_SALT
37 | if (salt === null) {
38 | if (process.argv.length > 3) {
39 | salt = process.argv[3];
40 | } else {
41 | salt = '';
42 | }
43 | console.log('Proceeding with password "' + password + '" and salt "' + salt + '".');
44 | } else {
45 | console.log('Proceeding with password "' + password + '" and default salt "' + salt + '".');
46 | }
47 |
48 | const params = {
49 | passphrase : password,
50 | salt : salt,
51 | progress_hook : logOutput
52 | };
53 |
54 | var startedScrypt = false;
55 | var startedPbkdf2 = false;
56 | var scryptBar;
57 | var pbkdf2Bar;
58 | var lastProgress = 0;
59 | function logOutput(progress) {
60 | if (progress.what === 'scrypt') {
61 | if (startedScrypt) {
62 | scryptBar.tick(progress.i - lastProgress);
63 | lastProgress = progress.i;
64 | if (lastProgress === progress.total) {
65 | lastProgress = 0;
66 | }
67 | } else {
68 | scryptBar = new ProgressBar('Scrypt: [:bar] :percent', {
69 | complete: '#',
70 | incomplete: ' ',
71 | total: 524288
72 | });
73 | startedScrypt = true;
74 | }
75 | }
76 | if (progress.what === 'pbkdf2') {
77 | if (startedPbkdf2) {
78 | pbkdf2Bar.tick(progress.i - lastProgress);
79 | lastProgress = progress.i;
80 | if (lastProgress === progress.total) {
81 | lastProgress = 0;
82 | }
83 | } else {
84 | pbkdf2Bar = new ProgressBar('PBKDF2: [:bar] :percent', {
85 | complete: '#',
86 | incomplete: ' ',
87 | total: 65536
88 | });
89 | startedPbkdf2 = true;
90 | }
91 | }
92 | }
93 |
94 | function done(res) {
95 | var acnt = res.address;
96 | var scrt = res.secret;
97 | console.log('Ripple Address : ' + res.address);
98 | console.log('Ripple Secret : ' + res.secret);
99 | console.log('///// ADVANCED /////');
100 | console.log('Raw Private Key : ' + res.privateKey);
101 | console.log('Raw Public Key : ' + res.publicKey);
102 | display(scrt, acnt);
103 | }
104 |
105 | warp(params, done);
106 |
107 | ///////////////////////////////////////////////////////////
108 |
109 | function display(scrt, acnt) {
110 | var app = express();
111 |
112 | app.get('/', function(req, res) {
113 |
114 | res.writeHead(200, { 'Content-Type': 'text/html' });
115 |
116 | // display it in a web browser
117 | var html = "";
118 | html += "XRPtoolkit by Duke67";
119 | html += "";
120 |
121 | html += "
XRPtoolkit by Duke67
";
122 | html += "
RippleWarpWallet by termhn
";
123 | html += "
Ripple Account was extracted:
";
124 |
125 | var opts = {
126 | errorCorrectionLevel: 'H',
127 | type: 'image/png',
128 | scale: 10
129 | };
130 |
131 | // generate QR code of Ripple Address (public)
132 | qrcode.toDataURL(acnt, opts, function (err, url1) {
133 |
134 | // display it in the web browser
135 | html += "
";
136 | html += "Ripple Account:
";
137 | html += acnt + " ";
138 | html += " ";
139 | html += "
";
140 | });
141 |
142 | // generate QR code of Ripple Secret (private)
143 | opts.color.dark = '#F00'; // show Ripple secret in RED
144 | opts.scale = 5; // make Ripple secret SMALLER than account
145 | qrcode.toDataURL(scrt, opts, function (err2, url2) {
146 |
147 | // display it in the web browser
148 | html += "
";
149 | html += "Ripple Secret:
";
150 |
151 | // include script to display Ripple Secret (initially hidden for security purposes)
152 | html += ""
155 |
156 | // Reveal button
157 | html += "";
158 |
159 | html += "
";
160 | html += scrt + " ";
161 | html += " ";
162 | html += "