From 13b024356c1cf78a87b213828e5f011064de4fd1 Mon Sep 17 00:00:00 2001 From: aspiring-aster Date: Thu, 21 Nov 2024 12:50:41 -0500 Subject: [PATCH] Refactor oauth code --- .gitignore | 1 + src/twim/utils/oauth1.nim | 47 +++++++++++++++++++++++++++------------ src/twim/v1_1/media.nim | 18 ++++----------- src/twim/v2/tweets.nim | 30 +++++-------------------- 4 files changed, 43 insertions(+), 53 deletions(-) diff --git a/.gitignore b/.gitignore index c0613e2..d9bd452 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ nimblecache/ htmldocs/ shell.nix examples/example +examples/myexample* diff --git a/src/twim/utils/oauth1.nim b/src/twim/utils/oauth1.nim index 3eeb38a..97e0d2d 100644 --- a/src/twim/utils/oauth1.nim +++ b/src/twim/utils/oauth1.nim @@ -1,4 +1,4 @@ -import std/[strformat,random,strutils, base64] +import std/[strformat, random, strutils, base64, times] import ../utils/xapi import nimcrypto @@ -13,25 +13,25 @@ proc percentEncode(s: string): string = result.add(toHex(ord(c), 2)) # Random string for oauth_nonce -proc OauthNonce*(): string = +proc OauthNonce(): string = const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" result = "" for _ in 0 .. 10: result.add(alphabet[rand(alphabet.high)]) -proc OauthSignature*(xAPI: XAPI, httpMethod:string, endpoint:string, text: string, oAuthNonce: string, timeStamp: int):string = +proc OauthSignature(xAPI: XAPI, httpMethod: string, endpoint: string, + text: string, oAuthNonce: string, timeStamp: int): string = # Follow https://developer.x.com/en/docs/authentication/oauth-1-0a/creating-a-signature - # - var outputString:string = - fmt"{httpMethod}&"& + var outputString: string = + fmt"{httpMethod}&" & &"{percentEncode(endpoint)}&" - var paramString:string = - fmt"oauth_consumer_key={xAPI.consumerKey}&"& - &"oauth_nonce={oAuthNonce}&"& - &"oauth_signature_method=HMAC-SHA1&"& - &"oauth_timestamp={timeStamp}&"& - &"oauth_token={xAPI.accessToken}&"& + var paramString: string = + fmt"oauth_consumer_key={xAPI.consumerKey}&" & + &"oauth_nonce={oAuthNonce}&" & + &"oauth_signature_method=HMAC-SHA1&" & + &"oauth_timestamp={timeStamp}&" & + &"oauth_token={xAPI.accessToken}&" & &"oauth_version=1.0" paramString = percentEncode(paramString) @@ -40,11 +40,30 @@ proc OauthSignature*(xAPI: XAPI, httpMethod:string, endpoint:string, text: strin signatureBase = signatureBase.replace("+", "%20") - signatureBase = signatureBase.replace("%7E", "~") # Don't encode ~ + signatureBase = signatureBase.replace("%7E", "~") # Don't encode ~ - var signingKey:string = fmt"{xAPI.consumerSecret}&{xAPI.tokenSecret}" + var signingKey: string = fmt"{xAPI.consumerSecret}&{xAPI.tokenSecret}" let hmac = sha1.hmac(signingKey, signatureBase) result = base64.encode(hmac.data) result = percentEncode(result) + +proc generateOauthAuthString*(xapi: XAPI, endpoint: string, + content: string): string = + var oauthNonce: string = OauthNonce() + var timeStamp: int = toInt(epochTime()) + var oauthSignature: string = OauthSignature(xApi, "POST", endpoint, content, + oauthNonce, timeStamp) + + result = + &"OAuth oauth_consumer_key=\"{xAPI.consumerKey}\"," & + &"oauth_token=\"{xAPI.accessToken}\"," & + &"oauth_signature_method=\"HMAC-SHA1\"," & + &"oauth_timestamp=\"{timeStamp}\"," & + &"oauth_nonce=\"{oauthNonce}\"," & + &"oauth_version=\"1.0\"," & + &"oauth_signature=\"{oauthSignature}\"" + + + diff --git a/src/twim/v1_1/media.nim b/src/twim/v1_1/media.nim index 1ce71f0..73027f3 100644 --- a/src/twim/v1_1/media.nim +++ b/src/twim/v1_1/media.nim @@ -1,4 +1,4 @@ -import std/[httpclient, strformat, json, times, mimetypes] +import std/[httpclient] import ../utils/[xapi, oauth1] const MEDIA_ENDPOINT*: string = "https://upload.twitter.com/1.1/media/upload.json" @@ -6,21 +6,11 @@ const MEDIA_ENDPOINT*: string = "https://upload.twitter.com/1.1/media/upload.jso proc PostMedia*(xAPI: XAPI, fileName: string): string = var client: HttpClient = newHttpClient() - var oauthNonce: string = OauthNonce() - var timeStamp: int = toInt(epochTime()) - var oauthSignature:string = OauthSignature(xApi, "POST", MEDIA_ENDPOINT, fileName, oauthNonce, timeStamp) - var AUTH_STRING: string = - &"OAuth oauth_consumer_key=\"{xAPI.consumerKey}\"," & - &"oauth_token=\"{xAPI.accessToken}\"," & - &"oauth_signature_method=\"HMAC-SHA1\"," & - &"oauth_timestamp=\"{timeStamp}\"," & - &"oauth_nonce=\"{oauthNonce}\"," & - &"oauth_version=\"1.0\"," & - &"oauth_signature=\"{oauthSignature}\"" + let authString: string = generateOauthAuthString(xapi, MEDIA_ENDPOINT, fileName) client.headers = newHttpHeaders({"Content-Type": "multipart/form-data", - "authorization": AUTH_STRING}) + "authorization": authString}) var multipart = newMultipartData() multipart.addFiles({"media": fileName}) @@ -29,7 +19,7 @@ proc PostMedia*(xAPI: XAPI, fileName: string): string = var response: Response try: response = client.request(MEDIA_ENDPOINT, - httpMethod = HttpPost, multipart=multipart) + httpMethod = HttpPost, multipart = multipart) result = response.body finally: client.close() diff --git a/src/twim/v2/tweets.nim b/src/twim/v2/tweets.nim index 83749bc..4bfafb1 100644 --- a/src/twim/v2/tweets.nim +++ b/src/twim/v2/tweets.nim @@ -1,24 +1,14 @@ -import std/[httpclient, strformat, json, times, strutils] +import std/[httpclient, strformat, json] import ../utils/[xapi, oauth1] const TWEET_ENDPOINT*: string = "https://api.twitter.com/2/tweets" proc PostTextTweet*(xAPI: XAPI, text: string): string = var client: HttpClient = newHttpClient() - var oauthNonce: string = OauthNonce() - var timeStamp: int = toInt(epochTime()) - var oauthSignature:string = OauthSignature(xApi, "POST", TWEET_ENDPOINT, text, oauthNonce, timeStamp) - var AUTH_STRING: string = - &"OAuth oauth_consumer_key=\"{xAPI.consumerKey}\"," & - &"oauth_token=\"{xAPI.accessToken}\"," & - &"oauth_signature_method=\"HMAC-SHA1\"," & - &"oauth_timestamp=\"{timeStamp}\"," & - &"oauth_nonce=\"{oauthNonce}\"," & - &"oauth_version=\"1.0\"," & - &"oauth_signature=\"{oauthSignature}\"" + let authString: string = generateOauthAuthString(xapi, TWEET_ENDPOINT, text) client.headers = newHttpHeaders({"Content-Type": "application/json", - "authorization": AUTH_STRING}) + "authorization": authString}) let body = %*{ "text": &"{text}" } @@ -35,20 +25,10 @@ proc PostTextTweet*(xAPI: XAPI, text: string): string = proc PostTextTweet*(xAPI: XAPI, text: string, media_ids: seq[string]): string = var client: HttpClient = newHttpClient() - var oauthNonce: string = OauthNonce() - var timeStamp: int = toInt(epochTime()) - var oauthSignature:string = OauthSignature(xApi, "POST", TWEET_ENDPOINT, text, oauthNonce, timeStamp) - var AUTH_STRING: string = - &"OAuth oauth_consumer_key=\"{xAPI.consumerKey}\"," & - &"oauth_token=\"{xAPI.accessToken}\"," & - &"oauth_signature_method=\"HMAC-SHA1\"," & - &"oauth_timestamp=\"{timeStamp}\"," & - &"oauth_nonce=\"{oauthNonce}\"," & - &"oauth_version=\"1.0\"," & - &"oauth_signature=\"{oauthSignature}\"" + let authString: string = generateOauthAuthString(xapi, TWEET_ENDPOINT, text) client.headers = newHttpHeaders({"Content-Type": "application/json", - "authorization": AUTH_STRING}) + "authorization": authString}) let body = %*{