|
@@ -105,6 +105,8 @@
|
|
|
(setq request-message-level 'blather)
|
|
(setq request-message-level 'blather)
|
|
|
(setq request-message-level -1))
|
|
(setq request-message-level -1))
|
|
|
|
|
|
|
|
|
|
+;;; Get an oauth2 bearer token
|
|
|
|
|
+;;; https://developer.x.com/en/docs/authentication/api-reference/token
|
|
|
(defun exitter-get-access-token ()
|
|
(defun exitter-get-access-token ()
|
|
|
(let ((oauth-consumer-key-secret
|
|
(let ((oauth-consumer-key-secret
|
|
|
(base64-encode-string
|
|
(base64-encode-string
|
|
@@ -128,6 +130,13 @@
|
|
|
(message "Got error: %S" error-thrown)))
|
|
(message "Got error: %S" error-thrown)))
|
|
|
)))
|
|
)))
|
|
|
|
|
|
|
|
|
|
+;;; Use the twitter frontend flow and the oauth2 bearer token to
|
|
|
|
|
+;;; obtain a user oauth token aka user access token.
|
|
|
|
|
+
|
|
|
|
|
+;;; The official way of doing so is by oauth 1.0a documented at
|
|
|
|
|
+;;; https://developer.x.com/en/docs/authentication/oauth-1-0a, but
|
|
|
|
|
+;;; here we use the twitter frontend flow, similar to how one logs in
|
|
|
|
|
+;;; the twitter web client
|
|
|
(defun exitter-get-guest-token ()
|
|
(defun exitter-get-guest-token ()
|
|
|
(when exitter-debug (message "entering exitter-get-guest-token"))
|
|
(when exitter-debug (message "entering exitter-get-guest-token"))
|
|
|
(request exitter-url-activate
|
|
(request exitter-url-activate
|
|
@@ -299,12 +308,36 @@
|
|
|
(message "Got error: %S" error-thrown)))
|
|
(message "Got error: %S" error-thrown)))
|
|
|
))
|
|
))
|
|
|
|
|
|
|
|
-(defun exitter-get-sign-oauth (link url-params method)
|
|
|
|
|
- (let* ((oauth-params `(("oauth_consumer_key" . ,exitter-oauth-consumer-key)
|
|
|
|
|
- ("oauth_nonce" . ,(exitter-nonce))
|
|
|
|
|
|
|
+;;; Example at
|
|
|
|
|
+;;; https://developer.x.com/en/docs/authentication/oauth-1-0a/creating-a-signature
|
|
|
|
|
+;;; should produce signature "Ls93hJiZbQ3akF3HF3x1Bz8%2FzU4%3D"
|
|
|
|
|
+(defun exitter-example-sign-oauth ()
|
|
|
|
|
+ (exitter-get-sign-oauth
|
|
|
|
|
+ "https://api.x.com/1.1/statuses/update.json" ;link
|
|
|
|
|
+ '(("status" . "Hello Ladies + Gentlemen, a signed OAuth request!")
|
|
|
|
|
+ ("include_entities" . "true")) ;url-params
|
|
|
|
|
+ "POST" ;method
|
|
|
|
|
+ "xvz1evFS4wEEPTGEFPHBog" ;oauth-consumer-key
|
|
|
|
|
+ "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw" ;oauth-consumer-secret
|
|
|
|
|
+ "370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb" ;oauth-token
|
|
|
|
|
+ "LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE" ;oauth-token-secret
|
|
|
|
|
+ "kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg" ;oauth-nonce
|
|
|
|
|
+ "1318622958" ;oauth-timestamp
|
|
|
|
|
+ ))
|
|
|
|
|
+
|
|
|
|
|
+;;; see
|
|
|
|
|
+;;; https://developer.x.com/en/docs/authentication/oauth-1-0a/creating-a-signature
|
|
|
|
|
+;;; https://developer.x.com/en/docs/authentication/oauth-1-0a/authorizing-a-request
|
|
|
|
|
+(defun exitter-get-sign-oauth (link url-params method &optional
|
|
|
|
|
+ oauth-consumer-key oauth-consumer-secret
|
|
|
|
|
+ oauth-token oauth-token-secret
|
|
|
|
|
+ oauth-nonce oauth-timestamp)
|
|
|
|
|
+ (let* ((oauth-params `(("oauth_consumer_key" .
|
|
|
|
|
+ ,(or oauth-consumer-key exitter-oauth-consumer-key))
|
|
|
|
|
+ ("oauth_nonce" . ,(or oauth-nonce (exitter-nonce)))
|
|
|
("oauth_signature_method" . "HMAC-SHA1")
|
|
("oauth_signature_method" . "HMAC-SHA1")
|
|
|
- ("oauth_timestamp" . ,(format-time-string "%s" (current-time)))
|
|
|
|
|
- ("oauth_token" . ,exitter-oauth-token)
|
|
|
|
|
|
|
+ ("oauth_timestamp" . ,(or oauth-timestamp (format-time-string "%s" (current-time))))
|
|
|
|
|
+ ("oauth_token" . ,(or oauth-token exitter-oauth-token))
|
|
|
("oauth_version" . "1.0")))
|
|
("oauth_version" . "1.0")))
|
|
|
(all-params (sort (seq-concatenate 'list url-params oauth-params)
|
|
(all-params (sort (seq-concatenate 'list url-params oauth-params)
|
|
|
(lambda (a b) (string< (car a) (car b)))))
|
|
(lambda (a b) (string< (car a) (car b)))))
|
|
@@ -327,18 +360,19 @@
|
|
|
"\\+" "%20"
|
|
"\\+" "%20"
|
|
|
param-to-sign-unencoded)))))
|
|
param-to-sign-unencoded)))))
|
|
|
(to-sign (format "%s&%s&%s" method-up hexed-link param-to-sign))
|
|
(to-sign (format "%s&%s&%s" method-up hexed-link param-to-sign))
|
|
|
|
|
+ (signing-key (format "%s&%s"
|
|
|
|
|
+ (or oauth-consumer-secret
|
|
|
|
|
+ exitter-oauth-consumer-secret)
|
|
|
|
|
+ (or oauth-token-secret
|
|
|
|
|
+ exitter-oauth-token-secret)))
|
|
|
(signature (url-hexify-string
|
|
(signature (url-hexify-string
|
|
|
- (base64-encode-string
|
|
|
|
|
- (hmac-sha1 (encode-coding-string
|
|
|
|
|
- (format "%s&%s"
|
|
|
|
|
- exitter-oauth-consumer-secret
|
|
|
|
|
- exitter-oauth-token-secret)
|
|
|
|
|
- 'utf-8)
|
|
|
|
|
- (encode-coding-string to-sign 'utf-8)))))
|
|
|
|
|
|
|
+ (print (base64-encode-string
|
|
|
|
|
+ (exitter-hmac-sha1 (encode-coding-string signing-key 'utf-8)
|
|
|
|
|
+ (encode-coding-string to-sign 'utf-8))))))
|
|
|
)
|
|
)
|
|
|
- (message "PARAM-TO-SIGN-UNENC: %s" (prin1-to-string param-to-sign-unencoded))
|
|
|
|
|
- (message "PARAM-TO-SIGN: %s" (prin1-to-string param-to-sign))
|
|
|
|
|
- (message "TO-SIGN: %s" (prin1-to-string to-sign))
|
|
|
|
|
|
|
+ ;; (message "PARAM-TO-SIGN-UNENC: %s" (prin1-to-string param-to-sign-unencoded))
|
|
|
|
|
+ ;; (message "PARAM-TO-SIGN: %s" (prin1-to-string param-to-sign))
|
|
|
|
|
+ ;; (message "TO-SIGN: %s" (prin1-to-string to-sign))
|
|
|
(format "OAuth realm=\"http://api.twitter.com/\", oauth_signature=\"%s\", %s"
|
|
(format "OAuth realm=\"http://api.twitter.com/\", oauth_signature=\"%s\", %s"
|
|
|
signature
|
|
signature
|
|
|
(mapconcat
|
|
(mapconcat
|
|
@@ -403,6 +437,7 @@ ONEPLUS A3010 Build/PKQ1.181203.001)")
|
|
|
`(("variables" . ,variables)
|
|
`(("variables" . ,variables)
|
|
|
("features" . ,exitter-default-features)))))
|
|
("features" . ,exitter-default-features)))))
|
|
|
|
|
|
|
|
|
|
+;;; utilities
|
|
|
(require 'bindat)
|
|
(require 'bindat)
|
|
|
|
|
|
|
|
(defun exitter-nonce ()
|
|
(defun exitter-nonce ()
|
|
@@ -417,7 +452,8 @@ ONEPLUS A3010 Build/PKQ1.181203.001)")
|
|
|
|
|
|
|
|
(require 'sha1)
|
|
(require 'sha1)
|
|
|
|
|
|
|
|
-(defun hmac-sha1 (key message)
|
|
|
|
|
|
|
+;;; Source: https://www.emacswiki.org/emacs/HmacShaOne
|
|
|
|
|
+(defun exitter-hmac-sha1 (key message)
|
|
|
"Return an HMAC-SHA1 authentication code for KEY and MESSAGE.
|
|
"Return an HMAC-SHA1 authentication code for KEY and MESSAGE.
|
|
|
|
|
|
|
|
KEY and MESSAGE must be unibyte strings. The result is a unibyte
|
|
KEY and MESSAGE must be unibyte strings. The result is a unibyte
|