Skip to content

Commit

Permalink
Merge pull request #19 from cr0bar/main
Browse files Browse the repository at this point in the history
NSD Phoenix Edition
  • Loading branch information
blackcoffeexbt authored Jan 15, 2025
2 parents 4ef56dc + 9a96531 commit 4769bde
Show file tree
Hide file tree
Showing 52 changed files with 8,477 additions and 589 deletions.
366 changes: 366 additions & 0 deletions configure/nsd_config.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,366 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nostr Signing Device Configuration Tool</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f9;
color: #333;
}

header {
background-color: #6200ea;
color: white;
padding: 10px 20px;
text-align: center;
}

main {
padding: 20px;
width: 1000px;
margin: 0 auto;
}

h1 {
color: #ffffff;
}

h2 {
color: #6200ea;
}

div {
margin-bottom: 20px;
}

label {
font-weight: bold;
display: block;
margin-bottom: 5px;
color: #6200ea;
}

select, input[type="text"], input[type="password"], button {
width: 100%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}

button {
background-color: #6200ea;
color: white;
border: none;
cursor: pointer;
}

button:hover {
background-color: #4500b5;
}

#output {
background: #fff;
border: 1px solid #ccc;
padding: 10px;
border-radius: 4px;
max-height: 300px;
overflow-y: auto;
}

table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}

table, th, td {
border: 1px solid #ccc;
}

th, td {
padding: 10px;
text-align: left;
}

th {
background-color: #6200ea;
color: white;
}

td {
background-color: #f9f9f9;
}
</style>
</head>
<body>
<header>
<h1>Nostr Signing Device Configuration Tool</h1>
</header>
<main>
<div>
<button id="connectDevice">Connect to Device</button>
<button id="disconnectDevice">Disconnect</button>
</div>

<div>
<label for="commandDropdown">Select Command:</label>
<select id="commandDropdown">
<option value="/help">/help</option>
<option value="/ping">/ping</option>
<option value="/public-key">/public-key</option>
<option value="/sign-message">/sign-message</option>
<option value="/shared-secret">/shared-secret</option>
<option value="/restore">/restore</option>
<option value="/add-key">/add-key</option>
<option value="/remove-key">/remove-key</option>
<option value="/list-keys">/list-keys</option>
<option value="/switch-key">/switch-key</option>
<option value="/new-key">/new-key</option>
<option value="/name-key">/name-key</option>
<option value="/encrypt-message">/encrypt-message</option>
<option value="/decrypt-message">/decrypt-message</option>
<option value="/reboot">/reboot</option>
<option value="/wipe">/wipe</option>
</select>
</div>

<div>
<label for="argumentsInput">Enter Arguments:</label>
<input type="text" id="argumentsInput" placeholder="e.g., key data or index">
</div>

<div>
<button id="sendCommand">Send Command</button>
</div>

<div id="output">
<h2>Output</h2>
<pre id="responseOutput" style="background-color: #070707;color: #ffffff;padding: 10px;"></pre>
</div>

<h2>Command Descriptions</h2>
<table>
<thead>
<tr>
<th width="150px">Command</th>
<th width="250px">Argument 1</th>
<th width="250px">Argument 2</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>/help</td>
<td>None</td>
<td>None</td>
<td>Returns the help text.</td>
</tr>
<tr>
<td>/ping</td>
<td>None</td>
<td>None</td>
<td>Checks the connection with the device.</td>
</tr>
<tr>
<td>/public-key</td>
<td>None</td>
<td>None</td>
<td>Returns the public key in hex format.</td>
</tr>
<tr>
<td>/sign-message</td>
<td>Message to sign in hex format</td>
<td>None</td>
<td>Signs the provided message with the active private key.</td>
</tr>
<tr>
<td>/shared-secret</td>
<td>Public key in hex format</td>
<td>None</td>
<td>Generates a shared secret using the active private key.</td>
</tr>
<tr>
<td>/restore</td>
<td>Private key in hex format</td>
<td>None</td>
<td>Legacy support with v0.1 installer config button.</td>
</tr>
<tr>
<td>/add-key</td>
<td>Private key in hex format</td>
<td>None</td>
<td>Adds a new private key to the device.</td>
</tr>
<tr>
<td>/remove-key</td>
<td>Index of the key to remove</td>
<td>None</td>
<td>Removes the private key at the specified index.</td>
</tr>
<tr>
<td>/list-keys</td>
<td>None</td>
<td>None</td>
<td>Lists all stored private keys on the device.</td>
</tr>
<tr>
<td>/switch-key</td>
<td>Index of the key to switch to</td>
<td>None</td>
<td>Switch the currently active private key.</td>
</tr>
<tr>
<td>/new-key</td>
<td>None</td>
<td>None</td>
<td>Generates a new key on the device.</td>
</tr>
<tr>
<td>/name-key</td>
<td>The name of the key</td>
<td>None</td>
<td>Set the name of a key. Blank removes the name.</td>
</tr>
<tr>
<td>/encrypt-message</td>
<td>3rd party public key in hex format</td>
<td>The message to encrypt</td>
<td>Encrypts the message on the device (NIP-04) and returns the encrypted message.</td>
</tr>
<tr>
<td>/decrypt-message</td>
<td>3rd party public key in hex format</td>
<td>The message to decrypt</td>
<td>Decrypts the message on the device (NIP-04) and returns the decrypted message.</td>
</tr>
<tr>
<td>/reboot</td>
<td>None</td>
<td>None</td>
<td>Reboots the device.</td>
</tr>
<tr>
<td>/wipe</td>
<td>None</td>
<td>None</td>
<td>Erases the device. All keys and config is removed.</td>
</tr>
</tbody>
</table>
</main>

<script>
let port;
let reader;
let writer;

async function connectDevice() {
try {
port = await navigator.serial.requestPort();
await port.open({ baudRate: 9600 });

const decoder = new TextDecoderStream();
const inputDone = port.readable.pipeTo(decoder.writable);
reader = decoder.readable.getReader();

const encoder = new TextEncoderStream();
const outputDone = encoder.readable.pipeTo(port.writable);
writer = encoder.writable.getWriter();

// Wait for the device to initialize if needed
setTimeout(() => {
readLoop();
}, 500); // Delay to allow device to send initial data (adjust as necessary)

alert("Device connected!");
} catch (err) {
console.error('Failed to connect device:', err);
alert('Failed to connect device.');
}
}

async function disconnectDevice() {
try {
if (reader) {
reader.cancel();
await reader.releaseLock();
}
if (writer) {
await writer.close();
await writer.releaseLock();
}
if (port) {
await port.close();
}
alert("Device disconnected!");
} catch (err) {
console.error('Failed to disconnect device:', err);
alert('Failed to disconnect device.');
}
}

async function readLoop() {
let buffer = ""; // Buffer to accumulate incomplete lines
try {
while (port && port.readable && reader) {
const { value, done } = await reader.read();
if (done) {
console.log("Reader done.");
break;
}
if (value) {
buffer += value; // Append received chunk to the buffer
let lines = buffer.split("\n"); // Split buffer into lines
buffer = lines.pop(); // Keep the last (incomplete) line in the buffer
for (let line of lines) {
const trimmedLine = line.trim(); // Trim whitespace
if (trimmedLine) {
document.getElementById("responseOutput").textContent += trimmedLine + "\n";
}
}
}
}
// Flush any remaining data in the buffer
if (buffer.trim()) {
document.getElementById("responseOutput").textContent += buffer.trim() + "\n";
}
} catch (err) {
console.error('Error reading from device:', err);
}
}

async function sendCommandToDevice(command) {
if (!writer) {
alert("Device is not connected.");
return;
}
try {
// Clear the output log before sending the command
document.getElementById("responseOutput").textContent = "";
await writer.write(command + "\n");
document.getElementById("responseOutput").textContent += `Sent: ${command}\n`;
} catch (err) {
console.error('Error sending command:', err);
alert('Failed to send command.');
}
}

document.getElementById('connectDevice').addEventListener('click', connectDevice);
document.getElementById('disconnectDevice').addEventListener('click', disconnectDevice);

document.getElementById('sendCommand').addEventListener('click', () => {
const selectedCommand = document.getElementById('commandDropdown').value;
const argumentsInput = document.getElementById('argumentsInput').value.trim();
const fullCommand = argumentsInput ? `${selectedCommand} ${argumentsInput}` : selectedCommand;
sendCommandToDevice(fullCommand);
});
</script>
</body>
</html>
Binary file added installer/firmware/esp32/v0.2/boot_app0.bin
Binary file not shown.
Binary file added installer/firmware/esp32/v0.2/bootloader.bin
Binary file not shown.
29 changes: 29 additions & 0 deletions installer/firmware/esp32/v0.2/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "Nostr Signing Device",
"version": "0.2",
"funding_url": "https://github.com/lnbits/nostr-signing-device",
"new_install_prompt_erase": true,
"builds": [
{
"chipFamily": "ESP32",
"parts": [
{
"path": "bootloader.bin",
"offset": 4096
},
{
"path": "snsd.ino.partitions.bin",
"offset": 32768
},
{
"path": "boot_app0.bin",
"offset": 57344
},
{
"path": "snsd.ino.bin",
"offset": 65536
}
]
}
]
}
Binary file added installer/firmware/esp32/v0.2/snsd.ino.bin
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 4769bde

Please sign in to comment.