How to store and retrieve private key - dapp - javascript

When a button is pressed, I send custom tokens to the user using the code below by signing and sending it from my account. The code works perfectly, however, how do I safely store and retrieve the "private key"? The code below is stored in a plain javascript file.
web3.eth.accounts.signTransaction(rawTransaction, "**MY PRIVATE KEY HERE**")
.then(signedTx => web3.eth.sendSignedTransaction(signedTx.rawTransaction))
.then(req => {
/* The trx was done. Write your actions here. For example, getBalance. */
getTokenBalanceOf(userAddress).then( balance => { console.log(userAddress + " Token Balance: " + balance); });
addCustomTokensToUsersMetaMask();
customTokenTransferCompleted();
return true;
})
I know there are ways like using .secret files, or storing it in environment variables, etc, but I can’t find a good tutorial on how to do it. I’m using regular html and javascript and no backend. If I use a backend to store the private key, how would I call it from within the js file?

Never mind, I figured it out. I created a .secret file, which contains my private key, which I imported into a nodejs file. I pasted the code above into the file, and the code was triggered when my smart contract event (Purchased) was emitted and captured (emitted on the front end, and captured in my nodejs file). And when using events in nodejs, I had to use:
var web3 = new Web3("ws://127.0.0.1:7545");
To connect to ganache with websockets.

Related

Can I generate a transaction on the server and send it to the client for payment

I have built a smart contract method to which I pass some sensitive data that needs to be stored on the blockchain and alter the state of the contract. I, the creator of the contract don't want to be the one paying for the fees of that transaction. I want the user on the browser to approve and pay for it.
However, I do not want to generate the transaction object on the browser as I want some of the data that will be passed to the contract to be hidden from the client. If I understand the web3 syntax correctly, in the code below, I'm doing just that
web3.eth.sendTransaction({
from: walletAddressOfTheUserThatWillPayForTheTransaction,
data: myContract.methods.changeState(..sensitive data...).encodeABI()
})
However I do not want the above to happen on the browser. In my head, the sequence of events should look like this (pseudocode):
// server
let transactionObject = {
from: walletAddressOfTheUserThatWillPayForTheTransaction,
data: myContract.methods.changeState(..sensitive data...).encodeABI()
}
sendToClient(encrypt(transactionObject))
// client
let encryptedTransactionObject = await fetchEncryptedTransactionObjectFromServer()
// this should open up Metamask for the user so that they may approve and finalise the transaction on the browser
web3.eth.sendTransaction(encryptedTransactionObject)
Is this possible ? Is there some other way of achieving this? Could you provide me with some hints about the actual syntax to be used?
However, I do not want to generate the transaction object on the browser as I want some of the data that will be passed to the contract to be hidden from the client.
Then you should not be using public blockchains in the first place, as all data on public blockchains, by definition, is public. Anyone can read it.

How to isolate a Gunjs database?

I've been trying out GunJs for a couple of days now and I'm really enjoying it. As a starter project I've followed the Fireship chat dapp video aimed at building your own chat.
Here's the issue, now that I've finished the tutorial I would like to create my own chat. However, for some reason if I get a 'chat' node within my own app it seems to pick up on the same 'chat' node as the tutorial one that is online.
onMount(() => {
// Get Messages in large chat
db.get('chat')
.map()
.once(async (data, id) => {
if (data) {
// key for E2E - to do: change for web3
const key = '#foo';
var message = {
//transform the data
who: await db.user(data).get('alias'),
what: (await SEA.decrypt(data.what, key)) + '',
when: GUN.state.is(data, 'what'),
};
if (message.what) {
messages = [...messages.slice(-100), message]
}
}
})
})
This is also the case if I change the encryption key (then the messages just become undefined). Multiple questions arise from this:
Are graph node names unique within the whole of GunDb?
How do you handle conflicts where two gun-based apps call on the same node name?
Is this problem generally solved through filtering using 'header' props?
How do I make it pick up on only my data?
Even if I've read most of the docs, there seems to be something I'm missing in my comprehension of how the graph is generally seperated between apps. Any insight on how this works would be much appreciated.
Are graph node names unique within the whole of GunDb?
Yes.
How do you handle conflicts where two gun-based apps call on the same node name?
You don't. The expected result will be, they will overwrite each other.
Is this problem generally solved through filtering using 'header' props?
I don't think it's the right way to do it.
How do I make it pick up on only my data?
Use your own relay server.
Conclusion :
gunDB doesn't really care about the who fetch / put the data. If you want to protect your data, use your own relay server (not a public one), and put data in your user space. user space is readonly to the public, but read/write for the owner.

Auth0 unable to get ID token / user metadata

I am currently working on adding Auth0 to a Vue.js/Node.js application and so far I have figured out how to allow users to register and log in (to /callback) and that seems to be working fine. However, I have manually added (will be automatic later on) some data to the user metadata section. I have the below code as a rule that is turned on. I can’t seem to get access to the data on the Vue.js end of things. What I’d like is to be able to get the user data and user metadata so I can store it in my front end.
Rule code
function (user, context, callback) {
const namespace = 'account_signup_type/';
const namespace2 = 'account_type';
context.idToken[namespace + 'is_new'] = (context.stats.loginsCount === 1);
context.idToken[namespace2] = user.account_type;
context.idToken.user = user;
callback(null, user, context);
}
Code I am trying in my Vue.js front end
getIdTokenClaims(o) {
return this.auth0Client.getIdTokenClaims(o);
}
Currently, this returns undefined
I ended up figuring it out, there was no namespace being created in the id_token which resulted in it not properly passing the data through to the Vue .js app. I added a namespace using a web address format with the domain extension cut off and it now works.

matrix-js-sdk setup and configuration

I am having some issues trying to connect to a matrix server using the matrix-js-sdk in a react app.
I have provided a simple code example below, and made sure that credentials are valid (login works) and that the environment variable containing the URL for the matrix client is set. I have signed into element in a browser and created two rooms for testing purposes, and was expecting these two rooms would be returned from matrixClient.getRooms(). However, this simply returns an empty array. With some further testing it seems like the asynchronous functions provided for fetching room, member and group ID's only, works as expected.
According to https://matrix.org/docs/guides/usage-of-the-matrix-js-sd these should be valid steps for setting up the matrix-js-sdk, however the sync is never executed either.
const matrixClient = sdk.createClient(
process.env.REACT_APP_MATRIX_CLIENT_URL!
);
await matrixClient.long("m.login.password", credentials);
matrixClient.once('sync', () => {
debugger; // Never hit
}
for (const room of matrixClient.getRooms()) {
debugger; // Never hit
}
I did manage to use the roomId's returned from await matrixClient.roomInitialSync(roomId, limit, callback), however this lead me to another issue where I can't figure out how to decrypt messages, as the events containing the messages sent in the room seems to be of type 'm.room.encrypted' instead of 'm.room.message'.
Does anyone have any good examples of working implementations for the matrix-js-sdk, or any other good resources for properly understanding how to put this all together? I need to be able to load rooms, persons, messages etc. and display these respectively in a ReactJS application.
It turns out I simply forgot to run startClient on the matrix client, resulting in it not fetching any data.

File System Access API: is it possible to store the fileHandle of a saved or loaded file for later use?

Working on an app that uses the new(ish) File System Access API, and I wanted to save the fileHandles of recently loaded files, to display a "Recent Files..." menu option and let a user load one of these files without opening the system file selection window.
This article has a paragraph about storing fileHandles in IndexedDB and it mentions that the handles returned from the API are "serializable," but it doesn't have any example code, and JSON.stringify won't do it.
File handles are serializable, which means that you can save a file handle to IndexedDB, or call postMessage() to send them between the same top-level origin.
Is there a way to serialize the handle other than JSON? I thought maybe IndexedDB would do it automatically but that doesn't seem to work, either.
Here is a minimal example that demonstrates how to store and retrieve a file handle (a FileSystemHandle to be precise) in IndexedDB (the code uses the idb-keyval library for brevity):
import { get, set } from 'https://unpkg.com/idb-keyval#5.0.2/dist/esm/index.js';
const pre = document.querySelector('pre');
const button = document.querySelector('button');
button.addEventListener('click', async () => {
try {
const fileHandleOrUndefined = await get('file');
if (fileHandleOrUndefined) {
pre.textContent =
`Retrieved file handle "${fileHandleOrUndefined.name}" from IndexedDB.`;
return;
}
// This always returns an array, but we just need the first entry.
const [fileHandle] = await window.showOpenFilePicker();
await set('file', fileHandle);
pre.textContent =
`Stored file handle for "${fileHandle.name}" in IndexedDB.`;
} catch (error) {
alert(error.name, error.message);
}
});
I have created a demo that shows the above code in action.
When a platform interface is [Serializable], it means it has associated internal serialization and deserialization rules that will be used by APIs that perform the “structured clone” algorithm to create “copies” of JS values. Structured cloning is used by the Message API, as mentioned. It’s also used by the History API, so at least in theory you can persist FileHandle objects in association with history entries.
In Chromium at the time of writing, FileHandle objects appear to serialize and deserialize successfully when used with history.state in general, e.g. across reloads and backwards navigation. Curiously, it seems deserialization may silently fail when returning to a forward entry: popStateEvent.state and history.state always return null when traversing forwards to an entry whose associated state includes one or more FileHandles. This appears to be a bug.
History entries are part of the “session” storage “shelf”. Session here refers to (roughly) “the lifetime of the tab/window”. This can sometimes be exactly what you want for FileHandle (e.g. upon traversing backwards, reopen the file that was open in the earlier state). However it doesn’t help with “origin shelf” lifetime storage that sticks around across multiple sessions. The only API that can serialize and deserialize FileHandle for origin-level storage is, as far as I’m aware, IndexedDB.
For those using Dexie to interface with IndexedDB, you will get an empty object unless you leave the primary key unnamed ('not inbound'):
db.version(1).stores({
test: '++id'
});
const [fileHandle] = await window.showOpenFilePicker();
db.test.add({ fileHandle })
This results in a record with { fileHandle: {} } (empty object)
However, if you do not name the primary key, it serializes the object properly:
db.version(1).stores({
test: '++'
});
const [fileHandle] = await window.showOpenFilePicker();
db.test.add({ fileHandle })
Result: { fileHandle: FileSystemFileHandle... }
This may be a bug in Dexie, as reported here: https://github.com/dfahlander/Dexie.js/issues/1236

Categories

Resources