v1.0.1: 💯 ECDSA Command line tools
This commit is contained in:
		
						commit
						0b21269c95
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | node_modules | ||||||
							
								
								
									
										162
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,162 @@ | |||||||
|  | [Eckles CLI](https://git.coolaj86.com/coolaj86/eckles-cli.js) | ||||||
|  | ========= | ||||||
|  | 
 | ||||||
|  | Sponsored by [Root](https://therootcompany.com). | ||||||
|  | Built for [ACME.js](https://git.coolaj86.com/coolaj86/acme.js) | ||||||
|  | and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js) | ||||||
|  | 
 | ||||||
|  | ECDSA (elliptic curve) tools. | ||||||
|  | 
 | ||||||
|  | ## Install | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | npm install -g eckles | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Table of Contents | ||||||
|  | ================= | ||||||
|  | 
 | ||||||
|  | * [x] Generate EC Keys | ||||||
|  | * [x] PEM to JWK | ||||||
|  | * [x] JWK to PEM | ||||||
|  | * [x] SSH "pub" format | ||||||
|  | * [ ] RSA | ||||||
|  |   * **Need RSA tools?** Check out [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js) | ||||||
|  | 
 | ||||||
|  | ## Generate EC (ECDSA/ECDH) Keypair | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | eckles [format] [curve|encoding] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### Generate ECDSA JWK | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | eckles [jwk] [P-256|P-384] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | # Default P-256 (prime256v1, secp256r1) | ||||||
|  | eckles jwk | ||||||
|  | 
 | ||||||
|  | # Use P-384 (secp384r1) | ||||||
|  | eckles jwk P-384 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### Generate ECDSA PEM | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | eckles [sec1|pkcs8|ssh] [P-256|P-384] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles sec1 | ||||||
|  | 
 | ||||||
|  | eckles pkcs8 P-256 | ||||||
|  | 
 | ||||||
|  | eckles ssh P-384 | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### Generate ECDSA DER | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | eckles [sec1|pkcs8] [der] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles sec1 der > privkey.ec.sec1.der 2> pub.ec.spki.der | ||||||
|  | 
 | ||||||
|  | eckles pkcs8 der > privkey.ec.pkcs8.der 2> pub.ec.spki.der | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Convert ECDSA PEM to JWK | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | eckles [pemfile] [public] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles privkey.pem > privkey.jwk.json | ||||||
|  | 
 | ||||||
|  | eckles pub.pem > pub.jwk.json | ||||||
|  | 
 | ||||||
|  | eckles privkey.pem public > pub.jwk.json | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles id_rsa > privkey.jwk.json | ||||||
|  | 
 | ||||||
|  | eckles id_rsa public > pub.jwk.json | ||||||
|  | 
 | ||||||
|  | eckles id_rsa.pub > pub.jwk.json | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Convert ECDSA JWK to PEM | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | eckles [jwk-keyfile] [format] | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles privkey.jwk.json sec1 > privkey.pem | ||||||
|  | 
 | ||||||
|  | eckles privkey.jwk.json pkcs8 > privkey.pem | ||||||
|  | 
 | ||||||
|  | eckles privkey.jwk.json spki > pub.pem | ||||||
|  | 
 | ||||||
|  | eckles privkey.jwk.json ssh > id_rsa.pub | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles pub.jwk.json spki > id_rsa.pub | ||||||
|  | 
 | ||||||
|  | eckles pub.jwk.json ssh > id_rsa.pub | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Convert ECDSA PEM to SSH | ||||||
|  | 
 | ||||||
|  | This is a two-step process, at the moment. | ||||||
|  | 
 | ||||||
|  | Only public keys are necessary, but private keys may be used. | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles privkey.pem > privkey.jwk.json | ||||||
|  | 
 | ||||||
|  | eckles privkey.jwk.json pkcs8 > id_rsa | ||||||
|  | 
 | ||||||
|  | eckles privkey.jwk.json ssh > id_rsa.pub | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles pub.pem > pub.jwk.json | ||||||
|  | 
 | ||||||
|  | eckles pub.jwk.json ssh > id_rsa.pub | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### Convert ECDSA SSH to PEM | ||||||
|  | 
 | ||||||
|  | This is a two-step process, at the moment. | ||||||
|  | 
 | ||||||
|  | Only public keys are necessary, but private keys may be used. | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles id_rsa > privkey.jwk.json | ||||||
|  | 
 | ||||||
|  | eckles privkey.jwk.json sec1 > privkey.pem | ||||||
|  | 
 | ||||||
|  | eckles privkey.jwk.json pkcs8 > privkey.pem | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | eckles id_rsa.pub > pub.jwk.json | ||||||
|  | 
 | ||||||
|  | eckles privkey.jwk.json spki > pub.pem | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Legal | ||||||
|  | ----- | ||||||
|  | 
 | ||||||
|  | [Eckles CLI](https://git.coolaj86.com/coolaj86/eckles-cli.js) | | ||||||
|  | MPL-2.0 | | ||||||
|  | [Terms of Use](https://therootcompany.com/legal/#terms) | | ||||||
|  | [Privacy Policy](https://therootcompany.com/legal/#privacy) | ||||||
							
								
								
									
										80
									
								
								bin/eckles.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										80
									
								
								bin/eckles.js
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,80 @@ | |||||||
|  | #!/usr/bin/env node
 | ||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var fs = require('fs'); | ||||||
|  | var Eckles = require('eckles'); | ||||||
|  | var ecdsacsr = require('ecdsa-csr'); | ||||||
|  | 
 | ||||||
|  | var infile = process.argv[2]; | ||||||
|  | var format = process.argv[3]; | ||||||
|  | var domains = process.argv[3]; | ||||||
|  | var key; | ||||||
|  | 
 | ||||||
|  | function errout(err) { | ||||||
|  |   console.error(err); | ||||||
|  |   process.exit(1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | if (!infile) { | ||||||
|  |   infile = 'jwk'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | if (-1 !== [ 'jwk', 'pem', 'json', 'der', 'sec1', 'pkcs8', 'spki', 'ssh' ].indexOf(infile)) { | ||||||
|  |   return Eckles.generate({ | ||||||
|  |     format: infile | ||||||
|  |   , namedCurve: format === 'P-384' ? 'P-384' : 'P-256' | ||||||
|  |   , encoding: format === 'der' ? 'der' : 'pem' | ||||||
|  |   }).then(function (key) { | ||||||
|  |     if ('der' === infile || 'der' === format) { | ||||||
|  |       key.private = key.private.toString('binary'); | ||||||
|  |       key.public = key.public.toString('binary'); | ||||||
|  |     } | ||||||
|  |     if ('jwk' === infile) { | ||||||
|  |       key.private = JSON.stringify(key.private, null, 2); | ||||||
|  |       key.public = JSON.stringify(key.public, null, 2); | ||||||
|  |     } | ||||||
|  |     console.info(key.private); | ||||||
|  |     // so that the pub key can be directed separately
 | ||||||
|  |     console.error(key.public); | ||||||
|  |     process.exit(0); | ||||||
|  |   }).catch(errout); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | if ('csr' === infile) { | ||||||
|  |   key = fs.readFileSync(format, 'ascii'); | ||||||
|  | } else { | ||||||
|  |   key = fs.readFileSync(infile, 'ascii'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | try { | ||||||
|  |   key = JSON.parse(key); | ||||||
|  | } catch(e) { | ||||||
|  |   // ignore
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if ('csr' === infile) { | ||||||
|  |   return ecdsacsr({ | ||||||
|  |     // don't remember which it was... whatever
 | ||||||
|  |     pem: key | ||||||
|  |   , key: key | ||||||
|  |   , jwk: key | ||||||
|  |   , domains: domains.split(/,/) | ||||||
|  |   }).then(function (csr) { | ||||||
|  |     console.info(csr); | ||||||
|  |   }).catch(errout); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | console.log(typeof key, key); | ||||||
|  | if ('string' === typeof key) { | ||||||
|  |   var pub = (-1 !== [ 'public', 'spki', 'pkix' ].indexOf(format)); | ||||||
|  |   return Eckles.import({ pem: key, public: (pub || format) }).then(function (jwk) { | ||||||
|  |     console.info(JSON.stringify(jwk, null, 2)); | ||||||
|  |   }).catch(errout); | ||||||
|  | } else { | ||||||
|  |   var pub = (-1 !== [ 'public', 'spki', 'pkix', 'ssh' ].indexOf(format)); | ||||||
|  |   if ('public' === format) { format = 'spki'; } | ||||||
|  |   return Eckles.export({ jwk: key, format: format, public: pub }).then(function (pem) { | ||||||
|  |     console.info(pem); | ||||||
|  |   }).catch(errout); | ||||||
|  | } | ||||||
							
								
								
									
										111
									
								
								lib/telemetry.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								lib/telemetry.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | // We believe in a proactive approach to sustainable open source.
 | ||||||
|  | // As part of that we make it easy for you to opt-in to following our progress
 | ||||||
|  | // and we also stay up-to-date on telemetry such as operating system and node
 | ||||||
|  | // version so that we can focus our efforts where they'll have the greatest impact.
 | ||||||
|  | //
 | ||||||
|  | // Want to learn more about our Terms, Privacy Policy, and Mission?
 | ||||||
|  | // Check out https://therootcompany.com/legal/
 | ||||||
|  | 
 | ||||||
|  | var os = require('os'); | ||||||
|  | var crypto = require('crypto'); | ||||||
|  | var https = require('https'); | ||||||
|  | var pkg = require('../package.json'); | ||||||
|  | 
 | ||||||
|  | // to help focus our efforts in the right places
 | ||||||
|  | var data = { | ||||||
|  |   package: pkg.name | ||||||
|  | , version: pkg.version | ||||||
|  | , node: process.version | ||||||
|  | , arch: process.arch || os.arch() | ||||||
|  | , platform: process.platform || os.platform() | ||||||
|  | , release: os.release() | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | function addCommunityMember(opts) { | ||||||
|  |   setTimeout(function () { | ||||||
|  |     var req = https.request({ | ||||||
|  |       hostname: 'api.therootcompany.com' | ||||||
|  |     , port: 443 | ||||||
|  |     , path: '/api/therootcompany.com/public/community' | ||||||
|  |     , method: 'POST' | ||||||
|  |     , headers: { 'Content-Type': 'application/json' } | ||||||
|  |     }, function (resp) { | ||||||
|  | 			// let the data flow, so we can ignore it
 | ||||||
|  |       resp.on('data', function () {}); | ||||||
|  |       //resp.on('data', function (chunk) { console.log(chunk.toString()); });
 | ||||||
|  | 			resp.on('error', function () { /*ignore*/ }); | ||||||
|  | 			//resp.on('error', function (err) { console.error(err); });
 | ||||||
|  |     }); | ||||||
|  | 		var obj = JSON.parse(JSON.stringify(data)); | ||||||
|  | 		obj.action = 'updates'; | ||||||
|  |     try { | ||||||
|  |       obj.ppid = ppid(obj.action); | ||||||
|  |     } catch(e) { | ||||||
|  |       // ignore
 | ||||||
|  |       //console.error(e);
 | ||||||
|  |     } | ||||||
|  | 		obj.name = opts.name || undefined; | ||||||
|  | 		obj.address = opts.email; | ||||||
|  | 		obj.community = 'node.js@therootcompany.com'; | ||||||
|  | 
 | ||||||
|  |     req.write(JSON.stringify(obj, 2, null)); | ||||||
|  |     req.end(); | ||||||
|  | 		req.on('error', function () { /*ignore*/ }); | ||||||
|  | 		//req.on('error', function (err) { console.error(err); });
 | ||||||
|  |   }, 50); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function ping(action) { | ||||||
|  |   setTimeout(function () { | ||||||
|  |     var req = https.request({ | ||||||
|  |       hostname: 'api.therootcompany.com' | ||||||
|  |     , port: 443 | ||||||
|  |     , path: '/api/therootcompany.com/public/ping' | ||||||
|  |     , method: 'POST' | ||||||
|  |     , headers: { 'Content-Type': 'application/json' } | ||||||
|  |     }, function (resp) { | ||||||
|  | 			// let the data flow, so we can ignore it
 | ||||||
|  |       resp.on('data', function () { }); | ||||||
|  |       //resp.on('data', function (chunk) { console.log(chunk.toString()); });
 | ||||||
|  | 			resp.on('error', function () { /*ignore*/ }); | ||||||
|  | 			//resp.on('error', function (err) { console.error(err); });
 | ||||||
|  |     }); | ||||||
|  | 		var obj = JSON.parse(JSON.stringify(data)); | ||||||
|  | 		obj.action = action; | ||||||
|  |     try { | ||||||
|  |       obj.ppid = ppid(obj.action); | ||||||
|  |     } catch(e) { | ||||||
|  |       // ignore
 | ||||||
|  |       //console.error(e);
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     req.write(JSON.stringify(obj, 2, null)); | ||||||
|  |     req.end(); | ||||||
|  | 		req.on('error', function (/*e*/) { /*console.error('req.error', e);*/ }); | ||||||
|  |   }, 50); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // to help identify unique installs without getting
 | ||||||
|  | // the personally identifiable info that we don't want
 | ||||||
|  | function ppid(action) { | ||||||
|  | 	var parts = [ action, data.package, data.version, data.node, data.arch, data.platform, data.release ]; | ||||||
|  | 	var ifaces = os.networkInterfaces(); | ||||||
|  | 	Object.keys(ifaces).forEach(function (ifname) { | ||||||
|  | 		if (/^en/.test(ifname) || /^eth/.test(ifname) || /^wl/.test(ifname)) { | ||||||
|  | 			if  (ifaces[ifname] && ifaces[ifname].length) { | ||||||
|  | 				parts.push(ifaces[ifname][0].mac); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}); | ||||||
|  |   return crypto.createHash('sha1').update(parts.join(',')).digest('base64'); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | module.exports.ping = ping; | ||||||
|  | module.exports.joinCommunity = addCommunityMember; | ||||||
|  | 
 | ||||||
|  | if (require.main === module) { | ||||||
|  | 	ping('install'); | ||||||
|  | 	//addCommunityMember({ name: "AJ ONeal", email: 'coolaj86@gmail.com' });
 | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | { | ||||||
|  |   "name": "eckles-cli", | ||||||
|  |   "version": "1.3.1", | ||||||
|  |   "lockfileVersion": 1, | ||||||
|  |   "requires": true, | ||||||
|  |   "dependencies": { | ||||||
|  |     "ecdsa-csr": { | ||||||
|  |       "version": "1.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/ecdsa-csr/-/ecdsa-csr-1.1.1.tgz", | ||||||
|  |       "integrity": "sha512-j0ssynuUi2ZPzkzEhUwPN5h5nOzJak7kExju29fEOVvIXvtU9o97puMNVQnEAM4uAM3u4G2Wp0YcusJKaSecCQ==" | ||||||
|  |     }, | ||||||
|  |     "eckles": { | ||||||
|  |       "version": "1.3.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/eckles/-/eckles-1.3.2.tgz", | ||||||
|  |       "integrity": "sha512-UBpiRqM/YqpuWSyQucnwmjWvd/umb1WvH2GEkdWiDRGzU6DLsjk8kHitmud4VtHXkggZXY8Oy+2zeMlqwYfIgw==" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | { | ||||||
|  |   "name": "eckles-cli", | ||||||
|  |   "version": "1.0.1", | ||||||
|  |   "description": "Command line ECDSA tools to generating key pairs and converting between JWK, various PEM formats, and SSH", | ||||||
|  |   "homepage": "https://git.coolaj86.com/coolaj86/eckles-cli.js", | ||||||
|  |   "main": "bin/eckles.js", | ||||||
|  |   "bin": { | ||||||
|  |     "eckles": "bin/eckles.js" | ||||||
|  |   }, | ||||||
|  |   "files": [ | ||||||
|  |     "bin", | ||||||
|  |     "fixtures", | ||||||
|  |     "lib", | ||||||
|  |     "test.sh" | ||||||
|  |   ], | ||||||
|  |   "directories": { | ||||||
|  |     "lib": "lib" | ||||||
|  |   }, | ||||||
|  |   "scripts": { | ||||||
|  |     "postinstall": "node lib/telemetry.js event:install", | ||||||
|  |     "test": "bash test.sh" | ||||||
|  |   }, | ||||||
|  |   "repository": { | ||||||
|  |     "type": "git", | ||||||
|  |     "url": "https://git.coolaj86.com/coolaj86/eckles-cli.js" | ||||||
|  |   }, | ||||||
|  |   "keywords": [ | ||||||
|  |     "EC", | ||||||
|  |     "ECDSA", | ||||||
|  |     "PEM", | ||||||
|  |     "JWK", | ||||||
|  |     "SSH", | ||||||
|  |     "tested", | ||||||
|  |     "working", | ||||||
|  |     "complete" | ||||||
|  |   ], | ||||||
|  |   "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", | ||||||
|  |   "license": "MPL-2.0", | ||||||
|  |   "dependencies": { | ||||||
|  |     "ecdsa-csr": "^1.1.1", | ||||||
|  |     "eckles": "^1.3.2" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								test.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								test.sh
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | set -e | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | echo "Generate" | ||||||
|  | node bin/eckles.js jwk > privkey.1.jwk.json 2> pub.1.jwk.json | ||||||
|  | node bin/eckles.js sec1 > privkey.2.sec1.pem 2> pub.2.spki.pem | ||||||
|  | node bin/eckles.js pkcs8 > privkey.3.pkcs8.pem 2> pub.3.spki.pem | ||||||
|  | node bin/eckles.js ssh > id_rsa 2> id_rsa.pub | ||||||
|  | echo "PASS" | ||||||
|  | 
 | ||||||
|  | # JWK | ||||||
|  | echo "" | ||||||
|  | echo "Read JWK" | ||||||
|  | node bin/eckles.js privkey.1.jwk.json > /dev/null | ||||||
|  | node bin/eckles.js privkey.1.jwk.json public > /dev/null | ||||||
|  | node bin/eckles.js pub.1.jwk.json > /dev/null | ||||||
|  | echo "PASS" | ||||||
|  | 
 | ||||||
|  | # SEC1 + SPKI | ||||||
|  | echo "" | ||||||
|  | echo "Read SEC1" | ||||||
|  | node bin/eckles.js privkey.2.sec1.pem > /dev/null | ||||||
|  | node bin/eckles.js privkey.2.sec1.pem public > /dev/null | ||||||
|  | node bin/eckles.js pub.2.spki.pem > /dev/null | ||||||
|  | echo "PASS" | ||||||
|  | 
 | ||||||
|  | # PKCS8 (SPKI already tested) | ||||||
|  | echo "" | ||||||
|  | echo "Read PKCS8" | ||||||
|  | node bin/eckles.js privkey.3.pkcs8.pem > /dev/null | ||||||
|  | node bin/eckles.js privkey.3.pkcs8.pem public > /dev/null | ||||||
|  | echo "PASS" | ||||||
|  | 
 | ||||||
|  | # SSH (PKCS8 + PUB) | ||||||
|  | echo "" | ||||||
|  | echo "Read SSH" | ||||||
|  | node bin/eckles.js privkey.3.pkcs8.pem > /dev/null | ||||||
|  | node bin/eckles.js id_rsa > /dev/null | ||||||
|  | node bin/eckles.js id_rsa public > /dev/null | ||||||
|  | node bin/eckles.js id_rsa.pub > /dev/null | ||||||
|  | echo "PASS" | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | echo "" | ||||||
|  | echo "Passed all tests" | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user