Change from Oauth2 to Oauth1

This commit is contained in:
2025-10-24 22:02:59 +09:00
parent 1a1b8b9077
commit c39b41a21f
3 changed files with 88 additions and 55 deletions

View File

@@ -2,7 +2,8 @@
"permissions": { "permissions": {
"allow": [ "allow": [
"Bash(tree:*)", "Bash(tree:*)",
"Bash(mvn clean compile:*)" "Bash(mvn clean compile:*)",
"WebFetch(domain:github.com)"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []

View File

@@ -20,13 +20,6 @@
</properties> </properties>
<dependencies> <dependencies>
<!-- Twitter API v2 Client -->
<dependency>
<groupId>com.twitter</groupId>
<artifactId>twitter-api-java-sdk</artifactId>
<version>2.0.3</version>
</dependency>
<!-- OpenAI Java Client --> <!-- OpenAI Java Client -->
<dependency> <dependency>
<groupId>com.theokanning.openai-gpt3-java</groupId> <groupId>com.theokanning.openai-gpt3-java</groupId>

View File

@@ -1,16 +1,12 @@
package com.voidcode.tweetbot.service; package com.voidcode.tweetbot.service;
import com.twitter.clientlib.TwitterCredentialsOAuth2; import com.fasterxml.jackson.databind.JsonNode;
import com.twitter.clientlib.api.TwitterApi; import com.fasterxml.jackson.databind.ObjectMapper;
import com.twitter.clientlib.ApiException; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.twitter.clientlib.model.TweetCreateRequest;
import com.twitter.clientlib.model.TweetCreateRequestMedia;
import com.twitter.clientlib.model.TweetCreateResponse;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
@@ -22,37 +18,26 @@ import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class TwitterService { public class TwitterService {
private static final Logger logger = LoggerFactory.getLogger(TwitterService.class); private static final Logger logger = LoggerFactory.getLogger(TwitterService.class);
private final TwitterApi apiInstance;
private final String apiKey; private final String apiKey;
private final String apiSecret; private final String apiSecret;
private final String accessToken; private final String accessToken;
private final String accessTokenSecret; private final String accessTokenSecret;
private final ObjectMapper objectMapper;
private static final String MEDIA_UPLOAD_URL = "https://upload.twitter.com/1.1/media/upload.json"; private static final String MEDIA_UPLOAD_URL = "https://upload.twitter.com/1.1/media/upload.json";
private static final String TWEET_CREATE_URL = "https://api.twitter.com/1.1/statuses/update.json";
public TwitterService(String apiKey, String apiSecret, String accessToken, String accessTokenSecret) { public TwitterService(String apiKey, String apiSecret, String accessToken, String accessTokenSecret) {
try { this.apiKey = apiKey;
this.apiKey = apiKey; this.apiSecret = apiSecret;
this.apiSecret = apiSecret; this.accessToken = accessToken;
this.accessToken = accessToken; this.accessTokenSecret = accessTokenSecret;
this.accessTokenSecret = accessTokenSecret; this.objectMapper = new ObjectMapper();
logger.info("Twitter service initialized successfully with OAuth 1.0a");
// Initialize Twitter API with OAuth 1.0a credentials
TwitterCredentialsOAuth2 credentials = new TwitterCredentialsOAuth2(
apiKey,
apiSecret,
accessToken,
accessTokenSecret
);
apiInstance = new TwitterApi(credentials);
logger.info("Twitter service initialized successfully");
} catch (Exception e) {
logger.error("Failed to initialize Twitter service", e);
throw new RuntimeException("Failed to initialize Twitter service: " + e.getMessage(), e);
}
} }
/** /**
@@ -74,9 +59,9 @@ public class TwitterService {
try { try {
logger.info("Posting tweet: {}", tweetText); logger.info("Posting tweet: {}", tweetText);
// Create the tweet request // Build query parameters
TweetCreateRequest tweetCreateRequest = new TweetCreateRequest(); Map<String, String> params = new TreeMap<>();
tweetCreateRequest.setText(tweetText); params.put("status", tweetText);
// Upload media if image path is provided // Upload media if image path is provided
if (imagePath != null && !imagePath.isEmpty()) { if (imagePath != null && !imagePath.isEmpty()) {
@@ -87,30 +72,64 @@ public class TwitterService {
try { try {
String mediaId = uploadMedia(imageFile); String mediaId = uploadMedia(imageFile);
logger.info("Media uploaded successfully. Media ID: {}", mediaId); logger.info("Media uploaded successfully. Media ID: {}", mediaId);
params.put("media_ids", mediaId);
// Attach media to tweet
TweetCreateRequestMedia media = new TweetCreateRequestMedia();
media.addMediaIdsItem(mediaId);
tweetCreateRequest.setMedia(media);
} catch (Exception e) { } catch (Exception e) {
logger.error("Failed to upload media, posting tweet without image", e); logger.error("Failed to upload media, posting tweet without image", e);
} }
} }
} }
// Post the tweet // Build URL with query parameters
TweetCreateResponse result = apiInstance.tweets().createTweet(tweetCreateRequest).execute(); StringBuilder urlBuilder = new StringBuilder(TWEET_CREATE_URL);
urlBuilder.append("?");
for (Map.Entry<String, String> entry : params.entrySet()) {
if (urlBuilder.charAt(urlBuilder.length() - 1) != '?') {
urlBuilder.append("&");
}
urlBuilder.append(urlEncode(entry.getKey())).append("=").append(urlEncode(entry.getValue()));
}
String fullUrl = urlBuilder.toString();
// Create OAuth header (include query params in signature)
String authHeader = generateOAuthHeader("POST", TWEET_CREATE_URL, params);
// Make HTTP request
HttpURLConnection connection = (HttpURLConnection) new URL(fullUrl).openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Authorization", authHeader);
connection.setRequestProperty("Content-Length", "0");
// Read response
int responseCode = connection.getResponseCode();
BufferedReader reader;
if (responseCode >= 200 && responseCode < 300) {
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
} else {
reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
}
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
if (responseCode != 200) {
logger.error("Failed to post tweet. Status code: {}, Response: {}", responseCode, response.toString());
throw new IOException("Failed to post tweet. Status code: " + responseCode + ", Response: " + response.toString());
}
// Parse tweet ID from response (v1.1 format)
JsonNode responseJson = objectMapper.readTree(response.toString());
String tweetId = responseJson.get("id_str").asText();
String tweetId = result.getData().getId();
logger.info("Tweet posted successfully. Tweet ID: {}", tweetId); logger.info("Tweet posted successfully. Tweet ID: {}", tweetId);
logger.info("View tweet at: https://twitter.com/user/status/{}", tweetId); logger.info("View tweet at: https://twitter.com/user/status/{}", tweetId);
return tweetId; return tweetId;
} catch (ApiException e) {
logger.error("Error posting tweet. Status code: {}, Response: {}",
e.getCode(), e.getResponseBody(), e);
throw new RuntimeException("Failed to post tweet: " + e.getMessage(), e);
} catch (Exception e) { } catch (Exception e) {
logger.error("Unexpected error posting tweet", e); logger.error("Unexpected error posting tweet", e);
throw new RuntimeException("Failed to post tweet: " + e.getMessage(), e); throw new RuntimeException("Failed to post tweet: " + e.getMessage(), e);
@@ -264,10 +283,30 @@ public class TwitterService {
public boolean verifyCredentials() { public boolean verifyCredentials() {
try { try {
logger.info("Verifying Twitter credentials..."); logger.info("Verifying Twitter credentials...");
// Try to get the authenticated user's information
apiInstance.users().findMyUser().execute(); String verifyUrl = "https://api.twitter.com/1.1/account/verify_credentials.json";
logger.info("Twitter credentials verified successfully"); String authHeader = generateOAuthHeader("GET", verifyUrl, new TreeMap<>());
return true;
HttpURLConnection connection = (HttpURLConnection) new URL(verifyUrl).openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", authHeader);
int responseCode = connection.getResponseCode();
if (responseCode == 200) {
logger.info("Twitter credentials verified successfully");
return true;
} else {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
logger.error("Failed to verify credentials. Status: {}, Response: {}", responseCode, response.toString());
return false;
}
} catch (Exception e) { } catch (Exception e) {
logger.error("Failed to verify Twitter credentials", e); logger.error("Failed to verify Twitter credentials", e);
return false; return false;