I am making a chrome extension that requires MetaMask authentication.
I started developing it as a web application, but as a chrome extension, it doesn't detect MetaMask...
This is my web application code right now:
function toggleButton() {
const loginButton = document.getElementById("login-button");
if (!window.ethereum) {
loginButton.innerText = "Install MetaMask";
loginButton.addEventListener("click", () => {
window.open("https://metamask.io");
});
return false;
}
loginButton.addEventListener("click", loginWithMetaMask);
}
async function loginWithMetaMask() {
const accounts = await window.ethereum.request({ method: "eth_requestAccounts" }).catch((e) => {
console.error(e.message);
return;
});
if (!accounts) {
return;
}
const userWallet = document.getElementById("user-wallet");
userWallet.innerText = accounts[0];
}
window.addEventListener("DOMContentLoaded", toggleButton);
Is there a way to migrate the web application to a chrome extension?
This is how to do it.
Install metamask-extension-provider in your project
https://github.com/MetaMask/extension-provider
You will need to use browserify to compile your plugin.
Create a custom connector like this
class customConnector extends Moralis.AbstractWeb3Connector {
async activate() {
const provider = createMetaMaskProvider();
if (!provider) {
console.error("MetaMask provider not detected.");
throw new Error("MetaMask provider not detected.");
}
const [accounts, chainId] = await Promise.all([
provider.request({
method: 'eth_requestAccounts',
}),
provider.request({ method: 'eth_chainId' }),
]);
const account = accounts[0] ? accounts[0].toLowerCase() : null;
this.chainId = provider.chainId;
this.account = provider.selectedAddress;
this.provider = provider;
this.subscribeToEvents(provider);
return { provider, chainId, account };
}
}
Now you can authenticate using MetaMask like this
Moralis.authenticate({ connector: customConnector })
I have created a small boilerplate of chrome extension with react and added metamask login and web3 support.
https://github.com/shaheem-khanzada/chrome-extension-react-metamask-boilerplate
so the problem is we cannot access window.eth... directly in the extension that is why metamask created a module called metamask-extension-provider but in order to run this we need to use browserify
compiler so in simple words, we need to write our own compiler that's why I created this boilerplate to help others it uses gulp to create task and then bundle files using browserify and babelify
Related
I wanted to use web3JS config without using external wallets like metamask. To handle automated functions using cron jobs which are supposed to run every week. Since metamask asks for permission to use send() method to remove that I wanted to use a account where I will upload private key and stuff. I got this code from internet it works for locally/browser wallets dont know where to edit.
import Web3 from "web3";
const getWeb3 = () =>
new Promise((resolve, reject) => {
// Wait for loading completion to avoid race conditions with web3 injection timing.
window.addEventListener("load", async () => {
// Modern dapp browsers...
if (window.ethereum) {
const web3 = new Web3(window.ethereum);
try {
// Request account access if needed
await window.ethereum.enable();
// Accounts now exposed
resolve(web3);
console.log("enabled", web3);
console.log("MetaMask injected");
} catch (error) {
reject(error);
}
}
// Legacy dapp browsers...
else if (window.web3) {
// Use Mist/MetaMask's provider.
const web3 = window.web3;
// const web3 = window.web3.currentProvider.enable();
console.log("Injected web3 detected.");
resolve(web3);
}
// Fallback to localhost; use dev console port by default...
else {
const provider = new Web3.providers.HttpProvider(
"http://127.0.0.1:7545"
);
const web3 = new Web3(provider);
console.log("No web3 instance injected, using Local web3.");
resolve(web3);
}
});
});
export default getWeb3;
solved it
const Web3 = require("web3");
const WalletProvider = require("#truffle/hdwallet-provider");
let provider = new WalletProvider({
mnemonic: {
phrase:
"*******",
},
providerOrUrl: "https://goerli.infura.io/v3/****************",
});
const web3 = new Web3(provider);
const fetch123 = async () => {
const accounts = await web3.eth.getAccounts();
console.log(accounts);
};
fetch123();
This question references the method examples in AWS SDK for Javascript documentation.
The examples on the page (ie. Describing a table) splits up the code into modules:
ddbClient.js (has configuration settings).
ddb_describetable.js (has code that actually runs the method).
In ddb_describetable.js, why is there an export in front of the "const params..." and the "const run = async"? Can you explain the purpose with a high level example/best practices in relation to AWS or nodejs (if examples/best practices apply)?
ddbClient.js
// Create service client module using ES6 syntax.
import { DynamoDBClient } from "#aws-sdk/client-dynamodb";
// Set the AWS Region.
const REGION = "REGION"; //e.g. "us-east-1"
// Create an Amazon DynamoDB service client object.
const ddbClient = new DynamoDBClient({ region: REGION });
export { ddbClient };
ddb_describetable.js
// Import required AWS SDK clients and commands for Node.js
import { DescribeTableCommand } from "#aws-sdk/client-dynamodb";
import { ddbClient } from "./libs/ddbClient.js";
// Set the parameters
export const params = { TableName: "TABLE_NAME" }; //TABLE_NAME
export const run = async () => {
try {
const data = await ddbClient.send(new DescribeTableCommand(params));
console.log("Success", data);
// console.log("Success", data.Table.KeySchema);
return data;
} catch (err) {
console.log("Error", err);
}
};
run();
The actual DescribeTableCommand code documentation (which doesn't show an example) doesn't imply that this structure should be used.
I want to connect a Solana wallet (phantom or any other) to a web application through the web3js library. I've read docs for most wallets and it seems like it's just as simple as await window.solana.request({ method: "connect" }); but window.solana is undefined in my case.
When I do console.log(window) I can see the Solana value with all its corresponding keys and values.
How can I do this?
I've found a working code that solved my issue. I am not sure what was the issue as I'm not very experienced with js, but the following code lets me connect to phantom.
I found this on StackOverflow on a similar thread, although I belive the original answer is missing some brackets.
Solana : Adding Sollet / Phantom Wallet Connect to my website - Steps?
const getProvider = async () => {
if ("solana" in window) {
await window.solana.connect(); // opens wallet to connect to
const provider = window.solana;
if (provider.isPhantom) {
console.log("Is Phantom installed? ", provider.isPhantom);
return provider;
}
} else {
document.write('Install https://www.phantom.app/');
}
};
window.onload = () => {
getProvider().then(provider => {
console.log('key', provider.publicKey.toString())
})
.catch(function(error){
console.log(error)
});
}
With your current implementation, everytime you refresh the app, you will get pop up to connect to the wallet. Instead you add {onlyIfTrusted:true} option to connect.
const getProvider = async () => {
if ("solana" in window) {
await window.solana.connect({onlyIfTrusted:true}); // opens wallet to connect to
const provider = window.solana;
if (provider.isPhantom) {
console.log("Is Phantom installed? ", provider.isPhantom);
return provider;
}
} else {
document.write('Install https://www.phantom.app/');
}
};
then instead of getting pop up when you reload the app, write a connection function to handle the connection when a user clicks on the button
const connectToWallet=async ()=>{
const {solana}=window
if(solana){
const response=await solana.connect()
console.log('address',response.publicKey.toString())
}
}
<button onClick={connectToWallet} >
Connect to Wallet
</button>
Now once user is connected, when you reload the app, it you wont get pop up to connect to the wallet
Is your website https enabled? If not then it won't work
I'm in the process of setting a graphql endpoint with servlerless/ lambda and am receiving an error when trying to connect to the graphql playground that comes with graphql-yoga. When I go to my route that has the playground (/playground) it launches the playground interface however it just says:
Server cannot be reached
In the top right of the playground. It's worth noting i'm using the makeRemoteExecutableSchema utility to proxy to another graphql endpoint (which is my CMS called Prismic). I don't believe this is the issue as I have successfully connected to it with the playground when testing on a normal express server.
Here is the code in my handler.js
'use strict';
const { makeRemoteExecutableSchema } = require('graphql-tools');
const { PrismicLink } = require("apollo-link-prismic");
const { introspectSchema } = require('graphql-tools');
const { ACCESS_TOKEN, CMS_URL } = process.env;
const { GraphQLServerLambda } = require('graphql-yoga')
const lambda = async () => {
const link = PrismicLink({
uri: CMS_URL,
accessToken: ACCESS_TOKEN
});
const schema = await introspectSchema(link);
const executableSchema = makeRemoteExecutableSchema({
schema,
link,
});
return new GraphQLServerLambda({
schema: executableSchema,
context: req => ({ ...req })
});
}
exports.playground = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const graphQl = await lambda();
return graphQl.playgroundHandler(event, context, callback);
};
I have followed this guide for getting it running up till here and am fairly sure i've followed similar steps for what applies to what i'm trying to do but can't seem to figure out where i've gone wrong.
Thanks,
Could you take a look at what version of the graphql-yoga package you are using?
I had a similar problem using the Apollo server in combination with Kentico Cloud Headless CMS and I found this issue:
https://github.com/prisma/graphql-yoga/issues/267
We're looking to develop an ElectronJS app for particular website automation at our desk job, which includes common tasks like login, form filling, report downloading etc.
We've tried basic tutorial of ElectronJS, Spectron, NightmareJS, Puppeteer etc and all of them work fine separately, but very less documentation (although open github issues) are available on integration of each other.
We want to achieve following:
Login state (session) should not be deleted on ElectronJS app closing and should be available on restart of app.
Few menu buttons which initiates some automation tasks like download, form fill etc on existing browserWindow
We don't need headless automation, where some magic happens behind the scene. We need menu/button click based actions/tasks on current page only.
NightmareJS, Puppeteer etc all seems to start their own instances of web pages (since because they were built for testing of standalone apps) but what we need is automation of existing BrowserWindows.
Is puppeteer or nightmarejs correct tools for such goals? If yes, any documentation?
Or else, should we inject our own native JS events like mouseclick etc events in console to perform action?
You can use puppeteer-core. core version by default does not download Chromium, which you do not need if you want to control an Electron app.
In the test you then call launch method, where you define electron as the executable file instead of Chromium, like in following snippet:
const electron = require("electron");
const puppeteer = require("puppeteer-core");
const delay = ms =>
new Promise(resolve => {
setTimeout(() => {
resolve();
}, ms);
});
(async () => {
try {
const app = await puppeteer.launch({
executablePath: electron,
args: ["."],
headless: false,
});
const pages = await app.pages();
const [page] = pages;
await page.setViewport({ width: 1200, height: 700 });
await delay(5000);
const image = await page.screenshot();
console.log(image);
await page.close();
await delay(2000);
await app.close();
} catch (error) {
console.error(error);
}
})();
Update for electron 5.x.y and up (currently up to 7.x.y, I did not test it on 8.x.y beta yet), where puppeteer.connect is used instead of launch method:
// const assert = require("assert");
const electron = require("electron");
const kill = require("tree-kill");
const puppeteer = require("puppeteer-core");
const { spawn } = require("child_process");
let pid;
const run = async () => {
const port = 9200; // Debugging port
const startTime = Date.now();
const timeout = 20000; // Timeout in miliseconds
let app;
// Start Electron with custom debugging port
pid = spawn(electron, [".", `--remote-debugging-port=${port}`], {
shell: true
}).pid;
// Wait for Puppeteer to connect
while (!app) {
try {
app = await puppeteer.connect({
browserURL: `http://localhost:${port}`,
defaultViewport: { width: 1000, height: 600 } // Optional I think
});
} catch (error) {
if (Date.now() > startTime + timeout) {
throw error;
}
}
}
// Do something, e.g.:
// const [page] = await app.pages();
// await page.waitForSelector("#someid")//
// const text = await page.$eval("#someid", element => element.innerText);
// assert(text === "Your expected text");
// await page.close();
};
run()
.then(() => {
// Do something
})
.catch(error => {
// Do something
kill(pid, () => {
process.exit(1);
});
});
Getting the pid and using kill is optional. For running the script on some CI platform it does not matter, but for local environment you would have to close the electron app manually after each failed try.
Simple demo repo:
https://github.com/peterdanis/electron-puppeteer-demo
Automation Script in Java using Selenium and ChromeDriver
package setUp;
import helper.Constants;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
public class Test {
public static void main(String[] args) {
System.setProperty(Constants.WebDriverType, Constants.WebDriverPath + Constants.WindowsDriver);
ChromeOptions opt = new ChromeOptions();
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("chromeOptions", opt);
capabilities.setBrowserName("chrome");
capabilities.setVersion("73.0.3683.121");
ChromeOptions options = new ChromeOptions();
options.merge(capabilities);
options.setBinary("C:\\\\Program Files\\\\Audio\\\\Audio-Configuration\\\\Audio-Configuration.exe");
options.setCapability("chromeOptions", options);
ChromeDriver driver = new ChromeDriver(options);
try {
Thread.sleep(5000);
WebElement webElement = driver.findElement(By.xpath(
"/html/body/app-root/mat-drawer-container/mat-drawer/div/app-bottom-side-nav/div/app-settings-nav/div/div/a/div"));
webElement.click();
} catch (Exception e) {
System.out.println("Exception trace");
System.out.println(e);
}
}
}
Automation Script in JavaScript using Spectron (built on top-of ChromeDriver and WebDriverIO).
const Application = require("spectron").Application;
const path =
"C:/Program Files/Audio/Audio-Configuration/Audio-Configuration.exe";
const myApp = new Application({
path: path,
chromeDriverArgs: ["--disable-extensions"],
env: {
SPECTRON: true,
ELECTRON_ENABLE_LOGGING: true,
ELECTRON_ENABLE_STACK_DUMPING: true
}
});
const windowClick = async app => {
await app.start();
try {
// Identifying by class name
await app.client.click(".ic-setting");
// Identifying by Id
// await app.client.click("#left-btn");
} catch (error) {
// Log any failures
console.error("Test failed", error.message);
}
// Stop the application
await app.stop();
};
windowClick(myApp);
Spectron is the best match for electron build applications.
You will have access to all electron API.we can start and stop your app by spectron only.
We can run both packaged app or with out even packaging.
https://electronjs.org/spectron
You can use Spectron but if you want to look at documentation, Spectron is using webdriverio which has good documentation.
I recommend you to use Spectron because I tried to automate my tests with java-selenium but it fails some of case. If you want to use selenium, write below code to set capabilities to setup electron app to chromedriver.
ChromeOptions options = new ChromeOptions();
options.setBinary(binaryPath);
options.addArguments("--app=" + argPath);
options.setCapability("chromeOptions", options);
driver = new ChromeDriver(options);
Hope this will help to you.
If integrating with electron nightmare is a very good library to achieve this even it will be ready to distribute with it, here is the following useful documentation for the same resource1
and