I'm developing an application that uses Twillios Programmable Video API.
I'm new to using Node JS, but the documentation has been fairly straightforward, however I still have a few questions.
Here's code I am referencing.
const AccessToken = require('twilio').jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
// Used when generating any kind of tokens
const twilioAccountSid = 'ACxxxxxxxxxx';
const twilioApiKey = 'SKxxxxxxxxxx';
const twilioApiSecret = 'xxxxxxxxxxxx';
const identity = 'user';
// Create Video Grant
const videoGrant = new VideoGrant({
room: 'cool room'
});
// Create an access token which we will sign and return to the client,
// containing the grant we just created
const token = new AccessToken(twilioAccountSid, twilioApiKey, twilioApiSecret);
token.addGrant(videoGrant);
token.identity = identity;
// Serialize the token to a JWT string
console.log(token.toJwt());
In this specific example provided by Twillio, the video grant which I assume is mandatory is explicitly referenced, however that would mean for this specific token generator, the users can only enter rooms of that name.
I was wondering if it was possible to reference the room before configuring the token. Something similar to how the identity is a variable that's entered into the function before the token is output.
In addition, are there any required dependencies or libraries when creating tokens outside of Twillios own function environment?
Any answers, suggestions, or references are greatly appreciated.
Twilio developer evangelist here.
It is possible to supply the room name as a variable too. You might want to create a function that can take an identity and room name as arguments and returns an access token. Something like this:
const AccessToken = require('twilio').jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
// Used when generating any kind of tokens
const twilioAccountSid = 'ACxxxxxxxxxx';
const twilioApiKey = 'SKxxxxxxxxxx';
const twilioApiSecret = 'xxxxxxxxxxxx';
function generateToken(identity, roomName) {
const videoGrant = new VideoGrant({
room: roomName
});
const token = new AccessToken(twilioAccountSid, twilioApiKey, twilioApiSecret);
token.addGrant(videoGrant);
token.identity = identity;
return token.toJwt();
}
Then you can use the function like:
const token = generateToken("Stefan", "StefansRoom");
Let me know if that helps at all.
Related
I am trying to create a token collection using the Aptos Typescript SDK.
const account = new AptosAccount(Uint8Array.from(Buffer.from(PRIVATE_KEY)), ACCOUNT_ADDR);
await tokenClient.createCollection(
account,
"A test collection 1",
"A test collection",
"https://google.com",
);
But I get the following error:
ApiError2: {"message":"Invalid transaction: Type: Validation Code: INVALID_AUTH_KEY","error_code":"vm_error","vm_error_code":2}
What am I doing wrong?
Tried replicating the Aptos official example but instead of creating a new account, I want to use an existing funded account.
Let's say you have a private key as a hex string, you can do it like this:
import { AptosAccount, HexString } from "aptos";
const privateKeyHex = "0xdcaf65ead38f7cf0eb4f81961f8fc7f9b7f1e2f45e2d4a6da0dbef85f46f6057";
const privateKeyBytes = HexString.ensure(privateKeyHex).toUint8Array();
const account = new AptosAccount(privateKeyBytes);
I had the same issue. I Finally found out that the problem is the address that is not match with private_key, and the private_key was not in ed25519 format.
Your keys must be generated with ed25519 curve, then you should create your address from that key. I used bip_utils library to create bip_private_key (with Near protocol which is also ed25519)then:
private_key = ed25519.PrivateKey.from_hex(bip_private_key)
I just want to add details to Daniel's answer about how you can get private key after creating wallet and then use it:
import { AptosAccount } from "aptos";
const wallet = new AptosAccount();
const privateKeyHex = wallet.toPrivateKeyObject().privateKeyHex;
// ...
const privateKeyBytes = HexString.ensure(privateKeyHex).toUint8Array();
const account = new AptosAccount(privateKeyBytes);
Trying to do a simple send and receive function in Solana with vanilla JS.
Below is my send function that works fine, and now I want a receive function.
Where the provider would get Solana transferred from my treasury wallet.
I'm not sure what approach I should have, just starting out. Is there a way to just move things around in this function? Or do I have to have a totally different approach?
Thanks!
async function transferSOL() {
// Detecing and storing the phantom wallet of the user (creator in this case)
var provider = phantom;
// Establishing connection
var connection = new web3.Connection(
web3.clusterApiUrl('devnet'),
);
var transaction = new web3.Transaction().add(
web3.SystemProgram.transfer({
fromPubkey: provider.publicKey,
toPubkey: treasuryWallet.publicKey,
lamports: 0.1 * web3.LAMPORTS_PER_SOL - 100
}),
);
// Setting the variables for the transaction
transaction.feePayer = await provider.publicKey;
let blockhashObj = await connection.getRecentBlockhash();
transaction.recentBlockhash = await blockhashObj.blockhash;
// Request creator to sign the transaction (allow the transaction)
let signed = await provider.signTransaction(transaction);
let signature = await connection.sendRawTransaction(signed.serialize());
await connection.confirmTransaction(signature);
}
If you want to transfer from your treasury to the user, then you must sign for treasuryWallet somehow. In your case, it looks like you already have the keypair available to you in your app, so you can simply do:
var transaction = new web3.Transaction().add(
web3.SystemProgram.transfer({
toPubkey: provider.publicKey,
fromPubkey: treasuryWallet.publicKey,
lamports: 0.1 * web3.LAMPORTS_PER_SOL - 100
}),
);
// Setting the variables for the transaction
transaction.feePayer = treasuryWallet.publicKey;
let blockhashObj = await connection.getRecentBlockhash();
transaction.recentBlockhash = await blockhashObj.blockhash;
// Request creator to sign the transaction (allow the transaction)
transaction.sign(treasuryWallet);
let signature = await connection.sendRawTransaction(transaction.serialize());
await connection.confirmTransaction(signature);
Note that this is very unsafe! Everyone who uses your web app has full access to the treasury funds if the keypair is exposed, since they can just sign all the transactions that they want with it.
I'm trying to verify a signature generated with Google's cloud KMS, but I keep getting invalid responses.
Here's how I'm testing it:
const versionName = client.cryptoKeyVersionPath(
projectId,
locationId,
keyRingId,
keyId,
versionId
)
const [publicKey] = await client.getPublicKey({
name: versionName,
})
const valueToSign = 'hola, que tal'
const digest = crypto.createHash('sha256').update(valueToSign).digest()
const [signResponse] = await client.asymmetricSign({
name: versionName,
digest: {
sha256: digest,
},
})
const valid = crypto.createVerify('sha256').update(digest).verify(publicKey.pem, signResponse.signature)
if (!valid) return console.log('INVALID SIGNATURE')
console.log('SIGNATURE IS VALID!')
// output: INVALID SIGNATURE
This code will always log 'INVALID SIGNATURE' unless I use the original message instead of its hash:
const valid = crypto.createVerify('sha256').update(valueToSign).verify(publicKey.pem, signResponse.signature) // true
But using a local private key, I'm able to sign messages and verify them using their hashes:
const valueToSign = 'hola, the tal'
const msgHash = crypto.createHash("sha256").update(valueToSign).digest('base64');
const signer = crypto.createSign('sha256');
signer.update(msgHash);
const signature = signer.sign(pk, 'base64');
const verifier = crypto.createVerify('sha256');
verifier.update(msgHash);
const valid = verifier.verify(pubKey, signature, 'base64');
console.log(valid) // true
Why is it? Is there something different about kms signatures?
Based on this example from the crypto module documentation and your observations, I'd say that you might've misunderstood how client.asymmetricSign works. Let's analyze what happens:
Your local private key code:
const valueToSign = 'hola, the tal'
// Create sha256 hash
const msgHash = crypto.createHash("sha256").update(valueToSign).digest('base64');
// Let signer sign sha256(hash)
const signer = crypto.createSign('sha256');
signer.update(msgHash);
const signature = signer.sign(pk, 'base64');
// We now got sign(sha256(hash))
// Let verifier verify sha256(hash)
const verifier = crypto.createVerify('sha256');
verifier.update(msgHash);
const valid = verifier.verify(pubKey, signature, 'base64');
console.log(valid) // true
We are verifying sign(sha256(hash)) using verify(sha256(hash)).
Your KMS code:
const valueToSign = 'hola, que tal'
// Create sha256 hash
const digest = crypto.createHash('sha256').update(valueToSign).digest()
// Let KMS sign the hash
const [signResponse] = await client.asymmetricSign({
name: versionName,
digest: {
sha256: digest, // we already say "we hashed our data using sha256"
},
});
// We now got `sign(hash)`, NOT `sign(sha256(hash))` (where hash == digest)
// Let verifier verify sha256(hash)
const valid = crypto.createVerify('sha256').update(digest).verify(publicKey.pem, signResponse.signature)
We are verifying sign(hash) using verify(sha256(hash)).
Basically, locally you are signing your hash and verifying the signed hash. With KMS you are signing your data and verifying the signed hash, which is actually your signed data, hence your 2nd attempt with .update(valueToSign) works.
Solution? Hash your sha256 hash again before letting KMS sign it, since KMS expects the sha256 hash of the to-be-signed data, while the crypto expects the to-be-signed data (which it'll hash itself given the algorithm you passed to createSign).
The answer is very similar to the one from Kevin but from a different point of view, in other words.
When you use crypto.createSign(<algorithm>) and crypto.createVerify(<algorithm>) you are indicating the digest algorithm that will be used for signature creation and verification, respectively.
When you call update on the returned Sign and Verify objects you need to provide your data as is, crypto will take care of digesting that information as appropriate when you sign or verify it later.
In contrast, the GCP KMS asymmetricSign operation requires a message digest produced with the designated algorithm over your original data as argument. This is why you need to calculate the message digest with crypto.createHash first.
But please, as indicated, be aware that this fact doesn't change the behavior of the crypto verification process, it always requires the original data as input, this is why your code works when you pass your original data without hashing.
Although you provided a working example in your question for reference the GCP documentation provides additional ones.
Is there any node package or something else to start (Run) an Azure Webjob from JS? I'm an automation guy and I want to start an Azure Webjob to change some statuses in the app. Manually I just press "Run", but I want to start the job using code. An option is to login in UI and press the run button using automation, but is not looking professional for me to do it from UI.
I saw some infos there, in Webjob properties like webhook, user, password. Maybe I can use somehow those things to trigger using code.
Thank you!
If you want to manage Azure WebJob with node, we can use the package azure-arm-website. The package provides the method runTriggeredWebJobWithHttpOperationResponse to run a trigger WebJob and the method startContinuousWebJobWithHttpOperationResponse to continuous WebJob.
For example
Create a service pricipal
az login
az account set --subscription "SUBSCRIPTION_ID"
az ad sp create-for-rbac --role "Contributor" --scopes "/subscriptions/<subscription_id>"
Code
const {
ApplicationTokenCredentials,
AzureEnvironment,
} = require("ms-rest-azure");
const { WebSiteManagementClient } = require("azure-arm-website");
const clientId = "<the sp appId>";
const tenant = "<you AD tenant domain>";
const clientSecret = "<the sp password>";
const subscriptionId = "";
const creds = new ApplicationTokenCredentials(clientId, tenant, clientSecret, {
environment: AzureEnvironment.Azure,
});
const client = new WebSiteManagementClient(creds, subscriptionId);
const rgName = "rg-webapp-demo";
const webName = "demo-200925164220";
const jobName = "test";
client.webApps
.runTriggeredWebJobWithHttpOperationResponse(rgName, webName, jobName)
.then((res) => {
console.log(res.response.statusMessage);
console.log(res.response.statusCode);
})
.catch((err) => {
throw err;
});
client.webApps.startContinuousWebJob
I know that to have a collection populated such as guilds and channels, the bot must have logged in already, i.e. it can be used inside command files as well as inside events. What I have is a module that will display my logs inside my control discord server, and I want to be able to reference this module inside my events as well as my commands.
I have tried importing the module inside of the events, as well as other options that would make sense.
This is the code inside my module
const Discord = require('discord.js')
const bot = new Discord.Client()
const CC = '../settings/control-center.json'
const CCFile = require(CC)
const GUILD = bot.guilds.get(CCFile.GUILD)
const STARTUP = bot.channels.get(CCFile.STARTUP)
const INFO = bot.channels.get(CCFile.INFO)
const ERRORS = bot.channels.get(CCFile.ERRORS)
const RESTART = bot.channels.get(CCFile.RESTART)
const EXECUTABLES = bot.channels.get(CCFile.EXECUTABLES)
class Control {
/**
* Implement control center logging
* #param {string} message - What to send to the startup channel
* #return {string} The final product being sent to the startup channel
*/
STARTUP(message) {
return STARTUP.send(`${message}`)
}
}
module.exports = Control
I want to be able to globally use this module/the functions inside, so that my code can be more compact. So how can I have it so that this code is only loaded once the bot is logged in?
In your module code, you are creating a new Discord client instance, and never calling the login method.
A better approach would be to pass the bot object in your method
module file
const CC = '../settings/control-center.json';
const CCFile = require(CC);
const GUILD = CCFile.GUILD;
const STARTUP = CCFile.STARTUP;
const INFO = CCFile.INFO;
const ERRORS = CCFile.ERRORS;
const RESTART = CCFile.RESTART;
const EXECUTABLES = CCFile.EXECUTABLES;
class Control {
startup(bot, message) {
return bot.channels.get(STARTUP).send(message);
}
}
module.exports = Control
app file
// Use the bot here
const Discord = require('discord.js')
const bot = new Discord.Client()
const control = require('path/to/control.js');
[...]
// to send a message when ready, try something like this
bot.on('ready', () => {
control.startup(bot, 'bot is ready');
});
// don't forget to login
bot.login('YOUR-TOKEN-HERE');