On the command line I generated a new key pair using the github-api-signature package's generateKeyPair function, providing a name and email of my GitHub account and a random passphrase.
I took the public part of the generated key pair and put it in my GitHub account on the keys page.
I took the private key and provided it to the snippet of code below.
The request to create the commit returns successfully as does the programmatic creation of the PR, but when I visit the commits page of the PR there is a box saying 'Unverified' with the message "The signature in this commit could not be verified. Someone may be trying to trick you."
I compared the GPG key ID it provides me on this page with those listed in my GitHub keys page and it matches, so why does it show my commit as unverified?
Example code:
const privateKey = '[GENERATED PRIVATE KEY]';
const passphrase = '[RANDOM PASSPHRASE FROM EARLIER]';
const author = {
name: '[NAME THAT MATCHES GITHUB]',
email: '[EMAIL THAT MATCHES GITHUB]',
date: new Date().toISOString(),
};
const commitPayload: CommitPayload = {
message: commitMessage,
author,
committer: { ...author },
tree: tree.data.sha,
parents: [branch.data.object.sha],
};
const signature = await githubApiSignature.createSignature(
commitPayload,
privateKey,
passphrase,
);
const result = await got(
`[GITHUB API URL]/repos/[USERNAME]/[REPO_NAME]/git/commits`,
{
protocol: 'https:',
method: 'POST',
body: {
...commitPayload,
signature,
},
json: true
},
);
This was caused by a trailing \n in the commit message which was trimmed by the library I was using to generate the signature but not by me before POSTing to GitHub.
Further information on how I debugged this, should it help anyone else further down the line:
Originally I tried using the openpgp library directly following the guide for creating and verifying detached signatures, and faced the same validity issue.
Knowing that the signature was verified locally I knew that I must be sending something to the GitHub API incorrectly. The Git Commits API provides some useful feedback in the verification block of the response:
verification: {
verified: boolean
reason: string
signature: string
payload: string
}
...as well as a little further information in the documentation page on what each of the reasons mean.
Further investigation of the payload (including simplifying all my values) led me to find that the message was at fault.
Related
having a problem that when I try to run my cloud function where my secret key is being perceived as invalid. I am 99.99% sure that it is the same as is in the Stripe dashboard and have copied and pasted 100 times so I think it is something else.
{success: false, error: Invalid API Key provided: sk_test_**********************************************************************************************************************************************************************************************************}
If anyone could help that would be fantastic.
Can you double check if there's any extra empty space characters being added to the API key that you specified in the cloud function? Or if you are reading the API key from a config file, try hardcode it directly to the code and see if it solves the problem.
Initial thoughts...
Ensure you have setup a restricted key with the specified security.
Could this be an issue with the secret manager, invalidating your key here and reconfiguring https://console.cloud.google.com/security/secret-manager?referrer=search&project={your-project-id} may fix the issue.
If you install a new instance, do you still have the same issue?
If you can run locally, does the key work ok in small nodejs project for example, depending on which extension you are using:
import Stripe from 'stripe';
// invoices extension: apiVersion: '2020-03-02',
// payments extension: apiVersion = '2020-08-27';
const stripe = new Stripe('sk_test_...', {
apiVersion: '2022-11-15',
});
const createCustomer = async () => {
const params: Stripe.CustomerCreateParams = {
description: 'test customer',
};
const customer: Stripe.Customer = await stripe.customers.create(params);
console.log(customer.id);
};
createCustomer();
The problem that we are facing is:
The webhook signature sent by slack in the request header is not matching with the calculated webhook signature at our server, but only for the first request that is made when the Zervise app for Slack is opened and any of the tab is accessed. From the next requests the signatures are matching.
Our back-end server supports both the following type of request body that slack is using:
application/json
application/x-www-form-urlencoded
Following is the back-end code for checking the slack webhook signature:
const slack = (req, res, next) => {
if (
!req.headers['x-slack-request-timestamp'] ||
Math.abs(
Math.floor(new Date().getTime() / 1000) -
+req.headers['x-slack-request-timestamp']
) > 300
)
return res.status(400).send('Request too old!');
const baseStr = `v0:${
req.headers['x-slack-request-timestamp']
}:${qs.stringify(req.body, {
format: 'RFC1738',
})}`;
const receivedSignature = req.headers['x-slack-signature'];
const expectedSignature = `v0=${crypto
.createHmac('sha256', env.SLACK_SIGNING_SECRET)
.update(baseStr, 'utf8')
.digest('hex')}`;
if (expectedSignature !== receivedSignature) {
console.log('WEBHOOK SIGNATURE MISMATCH');
return res.status(400).send('Error: Signature mismatch security error');
}
console.log('WEBHOOK VERIFIED');
next();
};
The screenshots of the console logs are added below. Each screenshot includes the request headers, the received signature from slack (receivedSignature) and the calculated signature at our server (expectedSignature). I have also tried to use the raw body of request to calculate the signature, but it is still not matching from the first request only.
Following are the screenshot list:
Screenshot of the console logs for the first request where the signatures are not matching: app opened and the first request from slack
Screenshot of the console logs for the subsequent request where the signatures are matching: subsequent requests from slack
The issue is resolved. I needed to use the request body in raw form instead of the encoded formats. Doing that solved the signature mismatch problem.
Please check the following article written by me, where I have described the process in detail: Verifying requests from Slack - The CORRECT method for Node.js
I'm following this guide to update Github's dependabot secrets using their newly released API.
There's a part that says I need to encrypt my secret value using a public key
...
const key = "base64-encoded-public-key";
const value = "plain-text-secret";
// Convert the message and key to Uint8Array's (Buffer implements that interface)
const messageBytes = Buffer.from(value);
const keyBytes = Buffer.from(key, 'base64');
...
My question is, where does this public key come from? I don't recall setting up any keys when configuring dependabot for my repo.
Looking through the dependabot API docs I realized there's also an endpoint to get your repository's public key which gives you the public key to be used. I missed it initially.
Im using flutter with the Amazo Cognito Identiy Dart Plugin
I am new to AWS and followed the sample code provided on the plugin's github page to create a new user but I keep getting the following error message:
CognitoClientException{statusCode: null, code: NetworkError, name: null, message: Failed host lookup: 'cognito-idp.us-east-1.amazonaws.com'}
I have read through a good chunck of the complete sample app and can't seem to find what I am overlooking. I thought that maybe I needed to include the android permission for internet (although the documentation didn't mention it); however I still got the same error code.
Below is the code for the method to sign up a new user. The variables cognitoUserPoolId and cognitoClientId are from a secret.dart file, and reference my user pool. The user pool allows users to sign up with a name, email address, and password. Besides that it uses the default settings.
final userPool = new CognitoUserPool(cognitoUserPoolId, cognitoClientId);
signUpUser(String name, String email, String password) async {
final userAttributes = [
new AttributeArg(name: 'name', value: name),
];
var data;
try {
print('attempting to sign user up');
data = await userPool.signUp(email, password, userAttributes: userAttributes);
} catch (e) {
print(e);
}
}
Edit: turns out what I was reading was the source code of the plugin, and not the example app. According to the example it seems that the uses-internet permission is actually required. Unfortunately as I stated earlier adding it did not fix the problem.
Update: I have found the solution. It turns out the emulator I was runnning was having issues connecting to the network. Stack Overflow question detailing how to fix that issue
I simply used a physical device and all seems to be working great!
How does reply.github.com work? I've noticed you can reply to Github emails, for example:
Reply-To: example/foobar <reply+000bafafcb72e8dc89884bda7ce639d101cc16b69010bcaa92cf0000000117ad897992a169ce14271668#reply.github.com>
X-Auto-Response-Suppress: All
reply+${84_chars}#reply.github.com
And that is enough to append your message:
particular Github issue
in your name or userID
My question is, what encoding is that?
It's not HMAC as I believe you need to send your unecrypted message with that encoding.
HMAC was the answer after all. There was no need to hide the data I was trying to validate. The message authentication code (MAC) becomes a signature component which I verify in my backend.
const crypto = require('crypto')
const secret = process.env.API_ACCESS_TOKEN
function genreply (bugID, secret) {
const hash = crypto.createHmac('sha256', secret)
.update(bugID)
.digest('hex')
return `reply+${bugID}-${hash}#example.com`
}
console.log(genreply('61825', secret))