Password Manager
Overview
This sample application represents a basic blockchain-based password manager. The app stores and retrieves encrypted, immutable passwords from the blockchain using mintBlue's SDK.
To improve the learning experience, we added three code challenges and their solutions. This approach is designed to help you become more familiar with using the mintBlue SDK.
Prerequisites
- â Create an SDK Access Token (see Quick Start)
- â Create a new project and copy your project ID
- đ§ Optional: Complete the mintBlue SDK Getting Started
- đ§ Optional: Understand Output Types
You have two options to run the code:
- Create a project on your machine and copy the code
- Play with the code in CodeSandBox
How does the password manager work?
Below, you can find the code for a basic blockchain-based password manager. The password manager leverages mintBlue's SDK to store encrypted transactions using your keys on the blockchain. You can then again use these keys to decrypt a transaction's content to retrieve the password for a given account.
âšī¸ The Non-Custodial Keys section in the docs explains in detail how this works.
const { Mintblue } = require("@mintblue/sdk");
// show the user how to use the app when they don't provide the right arguments
if (process.argv.length < 3 || !["get", "add"].includes(process.argv[2])) {
console.log("Usage:");
console.log("- Add/Update password: node manager.js add [account] [password]");
console.log("- Retrieve password: node manager.js get [account]");
process.exit();
}
const command = process.argv[2];
const account = process.argv[3];
let password = process.argv[4];
async function main() {
const sdkToken = "<YOUR-SDK-TOKEN>";
let client = await Mintblue.create({ token: sdkToken });
let projectId = "<YOUR-PROJECT-ID>";
if (command === "add") {
// store account and password encrypted on blockchain
const { txid } = await client.createTransaction({
project_id: projectId,
outputs: [
{
type: "data",
value: { account, password },
encrypt: true,
},
],
});
console.log(`Password stored encrypted in transaction: https://whatsonchain.com/tx/${txid}`);
}
if (command === "get") {
// get all of this project's transactions
const transactions = await client.listTransactions({ project_id: projectId });
// find password record for requested account and decrypt it
for (let i = 0; i < transactions.length; i++) {
const txn = await client.getTransaction({
txid: transactions[i].txid,
parse: true, // default is true
});
// Show decrypted password to user when found
if (txn.outputs[0].value.account === account) {
console.log(`Password for ${account} is: ${txn.outputs[0].value.password}`);
process.exit();
}
}
console.log(`Password not found for: ${account}`);
}
}
main();
To use the code, make sure to initialize npm
with npm init -y
and install the mintBlue SDK:
npm install @mintblue/sdk
Next, let's run the example.
How to run the example
Make sure to replace the <YOUR-SDK-TOKEN>
with your SDK Access Token and <YOUR-PROJECT-ID>
with your project ID. If you are running the code on your machine, name the file manager.js
.
To run the example, you can execute the file with node
. When you don't provide the required arguments, it will print how to use the password manager.
node manager.js
# Usage:
- Add/Update password: node manager.js add [account] [password]
- Retrieve password: node manager.js get [account]
- Add a new account
Let's store our PayPal account using the following command.
node manager.js add paypal mysecretpass
# Output
Password stored encrypted in transaction: https://whatsonchain.com/tx/246d5a0be20819c96c5e605ef721c6581acaceebba59c7aec52c66974b422915
- Retrieve password for an account
You can retrieve the password for your PayPal using the get
command.
node manager.js get paypal
# Output
Password for paypal is: mysecretpass
Cool, right? Now, let's get our hands dirty.
Challenges
Challenges allow you to learn about mintBlue's SDK in a playful way. Let's get started!
Challenge 1: Add tags
Explanation: We want the user to be able to add a tag when creating a new account. This allows for better filtering capabilities to find accounts. You need to accept an additional argument from the terminal to add the tag. Here's how you can do this:
# node manager.js add [account] [password] [tag]
const command = process.argv[2];
const account = process.argv[3];
let password = process.argv[4];
let tag = process.argv[5]; # Accept tag
Goal: You need to modify the data output to store the tag. You can use the Data Output how-to guide if you are unsure how to do this.
After adding the tagging behavior, we should be able to use the add
command like this with a finance
tag.
node manager.js add paypal mysecretpass finance
When verifying the transaction in the mintBlue Console, it should look like this:
[
{
"type": "data",
"encrypt": true,
"sign": false,
"value": {
"tag": "finance",
"account": "paypal",
"password": "mysecretpass"
}
},
{
"type": "payment",
"to": "1Juc9Tjmb6wc6yCaWFuB9QdEEQ621992ks",
"satoshis": 24850
}
]
Here's the full code solution:
Details
Solution 1
const { Mintblue } = require("@mintblue/sdk");
// show the user how to use the app when they don't provide the right arguments
if (process.argv.length < 3 || !["get", "add"].includes(process.argv[2])) {
console.log("Usage:");
console.log("- Add/Update password: node manager.js add [account] [password] [tag]");
console.log("- Retrieve password: node manager.js get [account]");
process.exit();
}
const command = process.argv[2];
const account = process.argv[3];
let password = process.argv[4];
let tag = process.argv[5];
async function main() {
const sdkToken = "<YOUR-SDK-TOKEN>";
let client = await Mintblue.create({ token: sdkToken });
let projectId = "<YOUR-PROJECT-ID>";
if (command === "add") {
// store key value object with account and password encrypted on blockchain
const { txid } = await client.createTransaction({
project_id: projectId,
outputs: [
{
type: "data",
value: { account, password, tag },
encrypt: true,
},
],
});
console.log(`Password stored encrypted in transaction: https://whatsonchain.com/tx/${txid}`);
}
if (command === "get") {
// get all of this project's transactions
const transactions = await client.listTransactions({ project_id: projectId });
// find password record for requested account and decrypt it
for (let i = 0; i < transactions.length; i++) {
const txn = await client.getTransaction({
txid: transactions[i].txid,
parse: true, // default is true
});
// Show decrypted password to user when found
if (txn.outputs[0].value.account === account) {
console.log(`Password for ${account} is: ${txn.outputs[0].value.password}`);
process.exit();
}
}
console.log(`Password not found for: ${account}`);
}
}
main();
Challenge 2: Storing a file with the password
Explanation: We want to store a relevant file containing information about the password with each password. To keep things simple, let's define a fixed Buffer output that you can use in your code.
const content = Buffer.from("Password information file");
**Goal: **You need to modify the outputs
for the add
command to store a file. You can use the File Output guide to learn how to store files and the Combine Outputs guide to learn how to combine differrent outputs.
Details
Solution 2
const { Mintblue } = require("@mintblue/sdk");
// show the user how to use the app when they don't provide the right arguments
if (process.argv.length < 3 || !["get", "add"].includes(process.argv[2])) {
console.log("Usage:");
console.log("- Add/Update password: node manager.js add [account] [password] [tag]");
console.log("- Retrieve password: node manager.js get [account]");
process.exit();
}
const command = process.argv[2];
const account = process.argv[3];
let password = process.argv[4];
let tag = process.argv[5];
async function main() {
const sdkToken = "<YOUR-SDK-TOKEN>";
let client = await Mintblue.create({ token: sdkToken });
let projectId = "<YOUR-PROJECT-ID>";
if (command === "add") {
// store key value object with account and password encrypted on blockchain
const { txid } = await client.createTransaction({
project_id: projectId,
outputs: [
{
type: "data",
value: { account, password, tag },
encrypt: true,
},
{
type: "file",
value: {
contentType: "text/plain",
content: Buffer.from("Password information file"),
},
},
],
});
console.log(`Password stored encrypted in transaction: https://whatsonchain.com/tx/${txid}`);
}
if (command === "get") {
// get all of this project's transactions
const transactions = await client.listTransactions({ project_id: projectId });
// find password record for requested account and decrypt it
for (let i = 0; i < transactions.length; i++) {
const txn = await client.getTransaction({
txid: transactions[i].txid,
parse: true, // default is true
});
// Show decrypted password to user when found
if (txn.outputs[0].value.account === account) {
console.log(`Password for ${account} is: ${txn.outputs[0].value.password}`);
process.exit();
}
}
console.log(`Password not found for: ${account}`);
}
}
main();
Challenge 3: List all accounts and passwords
Explanation: We want to list all our stored accounts and passwords. The output should use the following format ${account} - ${password}
.
paypal - mysecretpass
google - mysecretgooglepass
You can use the following command block. Make sure to add the list
command to the helper output.
if (process.argv.length < 3 || !["get", "add", "list"].includes(process.argv[2])) {
// [...]
console.log("- List all passwords: node manager.js list");
process.exit();
}
// [...]
if (command === "list") {
// list a project's passwords
}
Goal: Modify the code to print all accounts and passwords. You can take inspiration from the get
command block.
Details
Solution 3
const { Mintblue } = require("@mintblue/sdk");
// show the user how to use the app when they don't provide the right arguments
if (process.argv.length < 3 || !["get", "add", "list"].includes(process.argv[2])) {
console.log("Usage:");
console.log("- Add/Update password: node manager.js add [account] [password] [tag]");
console.log("- Retrieve password: node manager.js get [account]");
console.log("- List all passwords: node manager.js list");
process.exit();
}
const command = process.argv[2];
const account = process.argv[3];
let password = process.argv[4];
let tag = process.argv[5];
async function main() {
const sdkToken = "<YOUR-SDK-TOKEN>";
let client = await Mintblue.create({ token: sdkToken });
let projectId = "<YOUR-PROJECT-ID>";
if (command === "add") {
// store key value object with account and password encrypted on blockchain
const { txid } = await client.createTransaction({
project_id: projectId,
outputs: [
{
type: "data",
value: { account, password, tag },
encrypt: true,
},
{
type: "file",
value: {
contentType: "text/plain",
content: Buffer.from("Password information file"),
},
},
],
});
console.log(`Password stored encrypted in transaction: https://whatsonchain.com/tx/${txid}`);
}
if (command === "get") {
// get all of this project's transactions
const transactions = await client.listTransactions({ project_id: projectId });
// find password record for requested account and decrypt it
for (let i = 0; i < transactions.length; i++) {
const txn = await client.getTransaction({
txid: transactions[i].txid,
parse: true, // default is true
});
// Show decrypted password to user when found
if (txn.outputs[0].value.account === account) {
console.log(`Password for ${account} is: ${txn.outputs[0].value.password}`);
process.exit();
}
}
console.log(`Password not found for: ${account}`);
}
if (command === "list") {
// list a project's passwords
const transactions = await client.listTransactions({ project_id: projectId });
for (let i = 0; i < transactions.length; i++) {
const txn = await client.getTransaction({
txid: transactions[i].txid,
parse: true, // default is true
});
console.log(`${txn.outputs[0].value.account} - ${txn.outputs[0].value.password}`);
}
}
}
main();
That's it!