Skip to content
Snippets Groups Projects
Verified Commit 64967933 authored by Mateusz Tyszczak's avatar Mateusz Tyszczak :scroll:
Browse files

Allow encrypting and decrypting messages

parent ff98f154
No related branches found
No related tags found
No related merge requests found
Pipeline #117418 passed
{
"name": "@hiveio/metamask-snap",
"version": "1.0.1",
"version": "1.1.0",
"description": "Hive wallet extension allowing you to sign transactions using keys derived from your Metamask wallet",
"main": "./dist/bundle.js",
"files": [
......
{
"version": "1.0.1",
"version": "1.1.0",
"description": "Hive wallet extension allowing you to sign transactions using keys derived from your Metamask wallet",
"proposedName": "Hive Wallet",
"repository": {
......@@ -7,7 +7,7 @@
"url": "git+https://gitlab.syncad.com/hive/metamask-snap.git"
},
"source": {
"shasum": "FzpJXdDNOVkP9aESauH9YuVQCd0PdhJDR8AXmBblk2E=",
"shasum": "kHytM2WI19j6IpN1uBFbJpGp7okw+DdHd88p3KBaw30=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
......
import type { RpcRequest, RpcResponse } from './rpc';
import { decodeBuffer } from './snap/decodeBuffer';
import { encodeBuffer } from './snap/encodeBuffer';
import { getPublicKeys } from './snap/getPublicKeys';
import { signTransaction } from './snap/signTransaction';
......@@ -26,7 +28,17 @@ export const onRpcRequest = async ({
case 'hive_signTransaction':
return {
signatures: await signTransaction(origin, request.params.transaction, request.params.keys)
}
};
case 'hive_decrypt':
return {
buffer: await decodeBuffer(origin, request.params.buffer, request.params.firstKey, request.params.secondKey)
};
case 'hive_encrypt':
return {
buffer: await encodeBuffer(origin, request.params.buffer, request.params.firstKey, request.params.secondKey)
};
default:
throw new Error('Method not found.');
......
......@@ -24,6 +24,28 @@ export type SignTransactionRequest = {
};
}
export type SignBufferRequest = {
method: 'hive_encrypt';
params: {
buffer: string;
firstKey: KeyIndex;
secondKey?: KeyIndex;
};
}
export type DecodeBufferRequest = {
method: 'hive_decrypt';
params: {
buffer: string;
firstKey: KeyIndex;
secondKey?: KeyIndex;
};
}
export type BufferResponse = {
buffer: string;
}
export type GetPublicKeyResponse = {
publicKeys: PublicKeyData[];
}
......@@ -32,5 +54,5 @@ export type SignTransactionResponse = {
signatures: THexString[];
}
export type RpcRequest = GetPublicKeyRequest | SignTransactionRequest;
export type RpcResponse = GetPublicKeyResponse | SignTransactionResponse;
export type RpcRequest = GetPublicKeyRequest | SignTransactionRequest | SignBufferRequest | DecodeBufferRequest;
export type RpcResponse = GetPublicKeyResponse | SignTransactionResponse | BufferResponse;
import type { KeyIndex } from "../rpc";
import { getWax } from "../hive/wax";
import { remove0x } from "@metamask/utils";
import { keyIndexToPath } from "../utils/key-management";
import { getTempWallet } from "../hive/beekeeper";
import { ConfirmBufferDecode } from "./dialogs/ConfirmBufferDecode";
import { SLIP10Node } from "@metamask/key-tree";
import type { THexString } from "@hiveio/wax";
export const decodeBuffer = async (origin: string, buffer: THexString, firstKey: KeyIndex, secondKey?: KeyIndex): Promise<string> => {
const keys = secondKey ? [ firstKey, secondKey ] : [ firstKey ];
const confirmDecode = await ConfirmBufferDecode(origin, buffer, keys);
if(!confirmDecode)
throw new Error('User denied the buffer decode');
// The order is important: First create wax, then create wallet
const wax = await getWax();
const wallet = await getTempWallet();
try {
for(const key of keys) {
const snapResponse = await snap.request({
method: 'snap_getBip32Entropy',
params: {
curve: "secp256k1",
path: keyIndexToPath(key)
}
});
const node = await SLIP10Node.fromJSON(snapResponse);
if (!node.privateKey)
throw new Error('No private key found');
const wif = wax.convertRawPrivateKeyToWif(remove0x(node.privateKey));
await wallet.importKey(wif);
}
const response = wax.decrypt(wallet, buffer);
return response;
} finally {
wallet.close();
}
};
import { Bold, Copyable, Text, Box, Italic } from "@metamask/snaps-sdk/jsx";
import type { KeyIndex } from "../../rpc";
export const ConfirmBufferDecode = (origin: string, buffer: string, keys: KeyIndex[]) => snap.request({
method: 'snap_dialog',
params: {
type: 'confirmation',
content: (
<Box>
<Text>
<Bold>{ origin }</Bold> asked to decode a buffer:
</Text>
<Copyable value={ buffer } />
<Text>
Confirm if you want to sign it using your:
</Text>
{ keys.map(key => (<Text>
- <Bold>{key.role}</Bold> key (account index: <Italic>#{ String(key.accountIndex ?? 0) }</Italic>)
</Text>))}
</Box>
)
}
});
import { Bold, Copyable, Text, Box, Italic } from "@metamask/snaps-sdk/jsx";
import { KeyIndex } from "../../rpc";
export const ConfirmBufferSign = (origin: string, buffer: string, keys: KeyIndex[]) => snap.request({
method: 'snap_dialog',
params: {
type: 'confirmation',
content: (
<Box>
<Text>
<Bold>{ origin }</Bold> asked to sign a buffer:
</Text>
<Copyable value={ buffer } />
<Text>
Confirm if you want to sign it using your:
</Text>
{ keys.map(key => (<Text>
- <Bold>{key.role}</Bold> key (account index: <Italic>#{ String(key.accountIndex ?? 0) }</Italic>)
</Text>))}
</Box>
)
}
});
import { Bold, Copyable, Text, Box, Italic } from "@metamask/snaps-sdk/jsx";
import { KeyIndex } from "../../rpc";
export const ConfirmSign = (origin: string, transaction: string, keys: KeyIndex[]) => snap.request({
export const ConfirmTransactionSign = (origin: string, transaction: string, keys: KeyIndex[]) => snap.request({
method: 'snap_dialog',
params: {
type: 'confirmation',
......@@ -15,7 +15,7 @@ export const ConfirmSign = (origin: string, transaction: string, keys: KeyIndex[
Confirm if you want to sign it using your:
</Text>
{ keys.map(key => (<Text>
- <Bold>{key.role}</Bold> key (account index: <Italic>#{ String(key.accountIndex || 0) }</Italic>)
- <Bold>{key.role}</Bold> key (account index: <Italic>#{ String(key.accountIndex ?? 0) }</Italic>)
</Text>))}
</Box>
)
......
import type { KeyIndex } from "../rpc";
import { getWax } from "../hive/wax";
import { remove0x } from "@metamask/utils";
import { keyIndexToPath } from "../utils/key-management";
import { getTempWallet } from "../hive/beekeeper";
import { SLIP10Node } from "@metamask/key-tree";
import type { TPublicKey } from "@hiveio/wax";
import { ConfirmBufferSign } from "./dialogs/ConfirmBufferSign";
export const encodeBuffer = async (origin: string, buffer: string, firstKey: KeyIndex, secondKey?: KeyIndex): Promise<string> => {
const keys = secondKey ? [ firstKey, secondKey ] : [ firstKey ];
const confirmDecode = await ConfirmBufferSign(origin, buffer, keys);
if(!confirmDecode)
throw new Error('User denied the buffer decode');
// The order is important: First create wax, then create wallet
const wax = await getWax();
const wallet = await getTempWallet();
try {
const publicKeys: TPublicKey[] = [];
for(const key of keys) {
const snapResponse = await snap.request({
method: 'snap_getBip32Entropy',
params: {
curve: "secp256k1",
path: keyIndexToPath(key)
}
});
const node = await SLIP10Node.fromJSON(snapResponse);
if (!node.privateKey)
throw new Error('No private key found');
const wif = wax.convertRawPrivateKeyToWif(remove0x(node.privateKey));
const publicKey = await wallet.importKey(wif);
publicKeys.push(publicKey);
}
const response = wax.encrypt(wallet, buffer, ...(publicKeys as [TPublicKey]));
return response;
} finally {
wallet.close();
}
};
......@@ -3,7 +3,7 @@ import { getWax } from "../hive/wax";
import { remove0x } from "@metamask/utils";
import { keyIndexToPath } from "../utils/key-management";
import { getTempWallet } from "../hive/beekeeper";
import { ConfirmSign } from "./dialogs/ConfirmSign";
import { ConfirmTransactionSign } from "./dialogs/ConfirmTransactionSign";
import type { THexString } from "@hiveio/wax";
import { SLIP10Node } from "@metamask/key-tree";
......@@ -11,7 +11,7 @@ export const signTransaction = async (origin: string, transaction: string, keys:
if (keys.length < 1)
throw new Error('No keys provided');
const confirmSign = await ConfirmSign(origin, transaction, keys);
const confirmSign = await ConfirmTransactionSign(origin, transaction, keys);
if(!confirmSign)
throw new Error('User denied the transaction');
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment