Skip to content

Commit

Permalink
Merge branch 'release/0.9.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
koga73 committed Aug 9, 2024
2 parents 3f23e12 + 7b7c328 commit 296d80d
Show file tree
Hide file tree
Showing 20 changed files with 11,293 additions and 6,597 deletions.
34 changes: 21 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,33 @@ Download the executables from the [latest release](https://github.com/koga73/inc

## Usage

### Interactive mode

```
incypher
```

### Command line mode

##### Store seed phrase or keys

```
incypher store ravencoin
incypher store seed/ravencoin
incypher store bitcoin
incypher store seed/bitcoin
```

##### View seed phrase or key in console

```
incypher view ravencoin
incypher view seed/ravencoin
incypher view bitcoin
incypher view seed/bitcoin
```

##### Open seed phrase or key with file system default

```
incypher open ravencoin
incypher open seed/ravencoin
incypher open bitcoin
incypher open seed/bitcoin
```

##### List stores
Expand All @@ -54,23 +62,23 @@ incypher list
##### Delete store(s)

```
incypher delete ravencoin
incypher delete seed/ravencoin
incypher delete bitcoin
incypher delete seed/bitcoin
incypher delete seed
```

##### Import file

```
incypher import ./ravencoin.txt
incypher import ./ravencoin.txt seed/ravencoin
incypher import ./bitcoin.txt
incypher import ./bitcoin.txt seed/bitcoin
```

##### Export file

```
incypher export ravencoin
incypher export seed/ravencoin ./ravencoin.txt
incypher export bitcoin
incypher export seed/bitcoin ./bitcoin.txt
```

##### Change password
Expand All @@ -82,7 +90,7 @@ incypher password
##### Secure erase

```
incypher erase ./ravencoin.txt
incypher erase ./bitcoin.txt
incypher nuke
```

Expand Down
5,928 changes: 1,335 additions & 4,593 deletions _artifacts/icon-logo.ai

Large diffs are not rendered by default.

Binary file added _artifacts/icon-logo_large.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
227 changes: 227 additions & 0 deletions bin/arg-interface.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
//Node imports
import path from "path";
import readline from "readline";

//Local imports
import BaseInterface from "./base-interface.js";
import Utils from "../src/utils.js";

//package.json
import packageJson from "../package.json" assert {type: "json"};
const {name: packageName, version: packageVersion, author: packageAuthor} = packageJson;

//Misc constants
const EXAMPLE_NAME = "bitcoin";

class _class extends BaseInterface {
constructor(config, filePaths) {
super(config, filePaths);

this.logger = console;
}

//Override
async execute(args) {
const {filePath, defaultDir} = this;

const argIndex = 0;
const argsLen = args.length;
switch (args[argIndex]) {
case "store":
const storeNumArgs = 2 + argIndex;
if (argsLen < storeNumArgs) {
throw new Error("Store key required");
}
const storeKey = args[argIndex + 1];
const storeVal = await _prompt(`Please enter the value for "${storeKey}"`);
await this.store(storeKey, storeVal);
break;

case "view":
if (argsLen < 2 + argIndex) {
throw new Error("View key required");
}
const viewKey = args[argIndex + 1];
await this.view(viewKey);
break;

case "open":
if (argsLen < 2 + argIndex) {
throw new Error("Open key required");
}
const openKey = args[argIndex + 1];
await this.open(openKey);
break;

case "list":
await this.list();
break;

case "delete":
if (argsLen < 2 + argIndex) {
throw new Error("Delete key required");
}
const deleteKey = args[argIndex + 1];
await this.delete(deleteKey);
break;

case "import":
const importNumArgs = 2 + argIndex;
if (argsLen < importNumArgs) {
throw new Error("File required");
}
const importFile = args[argIndex + 1];
const importKey = argsLen > importNumArgs ? args[argIndex + 2] : path.parse(importFile).base;
await this.import(importFile, importKey);
break;

case "export":
const exportNumArgs = 2 + argIndex;
if (argsLen < exportNumArgs) {
throw new Error("Export key required");
}
const exportKey = args[argIndex + 1];
const exportFile = argsLen > exportNumArgs ? args[argIndex + 2] : path.parse(exportKey).base;
await this.export(exportKey, exportFile);
break;

case "password":
case "passwd":
await this.password();
break;

case "erase":
if (argsLen < 2 + argIndex) {
throw new Error("File required");
}
const eraseFile = args[argIndex + 1];
await this.erase(eraseFile);
break;

case "nuke":
const nukeConfirm = await _prompt(`Type "yes" to erase ${filePath} and ${defaultDir}`);
if (nukeConfirm == "yes") {
await this.nuke();
}
break;

case "config":
this.openConfig();
process.exit(0);
break;

case "?":
case "help":
this._showCommands();
break;

default:
//Import file(s)
if (await Utils.fsExists(args[argIndex])) {
await this.importMany(args.slice(argIndex));
await _prompt("Press enter to exit");
} else {
_showCommands();
await _prompt("Run this program from the command line\nPress enter to exit");
}
break;
}

return 0;
}

//Override
_prompt(question, options) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});

//https://stackoverflow.com/a/59727173/3610169
function _handler_readline_keypress(c, k) {
let len = rl.line.length;
readline.moveCursor(rl.output, -len, 0);
readline.clearLine(rl.output, 1);
rl.output.write("*".repeat(len));
}

if (options.hidden) {
rl.input.on("keypress", _handler_readline_keypress);
}
return new Promise((resolve, reject) => {
rl.question(`\n${question}\n> `, (input) => {
if (options.hidden) {
rl.input.off("keypress", _handler_readline_keypress);
}
resolve(input);
rl.close();
});
});
}

//Override
async _promptPassExisting(options) {
const {_prompt} = this;

return await _prompt("Enter the passphrase", {...options, hidden: true});
}

//Override
async _promptPassNew(options) {
const {_prompt, logger} = this;

const passphrase = await _prompt("Create a passphrase", {...options, hidden: true});
const confirm = await _prompt("Confirm the passphrase", {...options, hidden: true});
if (passphrase != confirm) {
throw new Error("Passphrase does not match");
}
if (passphrase == "") {
logger.warn("WARN: Empty password specified - the keystore will not be encrypted!");
} else {
logger.log("Passphrase accepted");
}
return passphrase;
}

_showCommands() {
logger.log("");
logger.log("Store seed phrase or keys");
logger.log(` ${packageName} store ${EXAMPLE_NAME}`);
logger.log(` ${packageName} store seed/${EXAMPLE_NAME}`);
logger.log("");
logger.log("View seed phrase or key in console");
logger.log(` ${packageName} view ${EXAMPLE_NAME}`);
logger.log(` ${packageName} view seed/${EXAMPLE_NAME}`);
logger.log("");
logger.log("Open seed phrase or key with file system default");
logger.log(` ${packageName} open ${EXAMPLE_NAME}`);
logger.log(` ${packageName} open seed/${EXAMPLE_NAME}`);
logger.log("");
logger.log("List stores");
logger.log(` ${packageName} list`);
logger.log("");
logger.log("Delete store(s)");
logger.log(` ${packageName} delete ${EXAMPLE_NAME}`);
logger.log(` ${packageName} delete seed/${EXAMPLE_NAME}`);
logger.log(` ${packageName} delete seed`);
logger.log("");
logger.log("Import file");
logger.log(` ${packageName} import ./${EXAMPLE_NAME}.txt`);
logger.log(` ${packageName} import ./${EXAMPLE_NAME}.txt seed/${EXAMPLE_NAME}`);
logger.log("");
logger.log("Export file");
logger.log(` ${packageName} export ${EXAMPLE_NAME}`);
logger.log(` ${packageName} export seed/${EXAMPLE_NAME} ./${EXAMPLE_NAME}.txt`);
logger.log("");
logger.log("Change password");
logger.log(` ${packageName} password`);
logger.log("");
logger.log("Secure erase");
logger.log(` ${packageName} erase ./${EXAMPLE_NAME}.txt`);
logger.log(` ${packageName} nuke`);
logger.log("");
logger.log("Edit config");
logger.log(` ${packageName} config`);
}
}
export default _class;
Loading

0 comments on commit 296d80d

Please sign in to comment.