'Making A Cloudflare Worker That Tweets Though My Twitter Developer APIs. Can't Get CryptoJS.HmacSHA1 to Create Signature for Fetch Request
I am making a Cloudflare Worker that Tweets from my Twitter Developer APIs whenever I make a blank GET request to the worker. At first you might think "that's easy just use npm's twitter-api-v2
," but that won't work because Cloudflare workers need to be in pure javascript/typescript and can't rely on any external modules. So I attempted to do this with the following code.
index.ts
import { handleRequest } from './handler'
addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request))
})
handler.ts
import * as CryptoJS from 'crypto-js'
function getRandomString(length) {
const randomChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for ( let i = 0; i < length; i++ ) {
result += randomChars.charAt(Math.floor(Math.random() * randomChars.length));
}
return result;
}
function hexToBase64(str) {
const stringChange = str.toString()
return btoa(String.fromCharCode.apply(null, stringChange.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
}
async function postTweet() {
const oauth_consumer_key = '<OAUTH CONSUMER KEY HERE>'
const oauth_consumer_secret = '<OAUTH CONSUMER SECRET HERE>'
const oauth_token = '<OAUTH TOKEN HERE>'
const oauth_token_secret = '<OAUTH TOKEN SECRET HERE>'
const oauth_signature_method = 'HMAC-SHA1'
const oauth_version = '1.0'
const oauth_nonce = getRandomString(42)
const oauth_timestamp = Math.round(Date.now() / 1000)
const endpointURL = 'https://api.twitter.com/1.1/statuses/update.json?status';
const tweetData = {
status: 'I am Tweeting this now'
}
const encodedTweet = encodeURIComponent(tweetData.status).replace(/!/g, '%21')
const params = 'POST&' + encodeURIComponent('https://api.twitter.com/1.1/statuses/update.json') + '&include_entities' + encodeURIComponent('=true&') + 'oauth_consumer_key' + encodeURIComponent('='+oauth_consumer_key+'&') + 'oauth_nonce' + encodeURIComponent('='+oauth_nonce+'&') + 'oauth_signature_method' + encodeURIComponent('='+oauth_signature_method+'&') + 'oauth_timestamp' + encodeURIComponent('='+oauth_timestamp+'&') + 'oauth_token' + encodeURIComponent('='+oauth_token+'&') + 'oauth_version' + encodeURIComponent('='+oauth_version+'&') + 'status' + encodeURIComponent('='+encodedTweet)
const signingKey = encodeURIComponent(oauth_consumer_secret) + '&' + encodeURIComponent(oauth_token_secret)
//////HMAC-SHA1 Functionality//////
const hexStr = CryptoJS.HmacSHA1(params, signingKey)
console.log(hexStr)
const signature = hexToBase64(hexStr)
const oauth_signature = encodeURIComponent(signature)
fetch('https://api.twitter.com/1.1/statuses/update.json', {
method: 'post',
headers: {
'Authorization': 'OAuth oauth_consumer_key="'+oauth_consumer_key+'",oauth_token="'+oauth_token+'",oauth_signature_method="HMAC-SHA1",oauth_timestamp="'+oauth_timestamp+'",oauth_nonce="'+oauth_nonce+'",oauth_version="1.0",oauth_signature="'+oauth_signature+'"',
'Content-Type': 'application/x-www-form-urlencoded' // 'application/json'
},
body: JSON.stringify(tweetData)
}).then(function(response) {
return response.json();
}).then(function(data) {
console.log('result:', data);
});
console.log('postTweet ran')
}
export async function handleRequest(request: Request): Promise<Response> {
await postTweet()
return new Response(`Hello worker! this is a ${request.method} request`, {
headers: { 'content-type': 'text/plain' },
});
}
But when I run the code with wrangler dev
and then do a blank GET request to http://127.0.0.1:8787
with Postman, I get this in my terminal:
<myusername>@<mycomputername> <myappname> % wrangler dev
👂 Listening on http://127.0.0.1:8787
🌀 Detected changes...
💁 Ignoring stale first change
[2022-04-24 15:42:37] GET <myappname>.<myworkername>.workers.dev/ HTTP/1.1 200 OK
{unknown object}
postTweet ran
^C
<myusername>@<mycomputername> <myappname> %
I noticed that the problem probably starts with the fact that const hexStr = CryptoJS.HmacSHA1(params, signingKey)
is failing. You can see in the output that console.log(hexStr)
is printing {unknown object}
What am I doing wrong? And how can I get my Cloudflare worker to Tweet upon request?
Solution 1:[1]
that won't work because Cloudflare workers need to be in pure javascript/typescript and can't rely on any external modules
That's not the case, Node.js support was announced recently: https://blog.cloudflare.com/node-js-support-cloudflare-workers/
There's also a list of libraries (from npm) that work with Workers: https://workers.cloudflare.com/works
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | RozenMD |