package org.apache.streams.instagram.api;
import org.apache.streams.instagram.config.InstagramOAuthConfiguration;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.StringJoiner;
import java.util.TreeSet;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/**
* Handles request signing to api.instagram.com.
*
* @see <a href="https://www.instagram.com/developer/secure-api-requests/">https://www.instagram.com/developer/secure-api-requests/</a>
*/
public class InstagramOAuthRequestSigner {
private static final Logger LOGGER = LoggerFactory.getLogger(InstagramOAuthRequestSigner.class);
private static final String oauth_signature_encoding = "UTF-8";
private static final String oauth_signature_method = "HmacSHA256";
InstagramOAuthConfiguration oAuthConfiguration;
public InstagramOAuthRequestSigner(InstagramOAuthConfiguration oauth) {
this.oAuthConfiguration = oauth;
}
/**
* generateSignature.
* @param uri uri
* @return String
*/
public String generateSignature(String uri) {
String request_path = uri.substring(0, uri.indexOf('?'));
String request_param_line = uri.substring(uri.indexOf('?') + 1);
String[] request_params = URLDecoder.decode(request_param_line).split("&");
Map<String,String> oauthParamMap = new HashMap<>();
oauthParamMap.put("access_token", oAuthConfiguration.getAccessToken());
Map<String,String> allParamsMap = new HashMap<>(oauthParamMap);
for ( String request_param : request_params ) {
String key = request_param.substring(0, request_param.indexOf('='));
String value = request_param.substring(request_param.indexOf('=') + 1, request_param.length());
allParamsMap.put(key, value);
}
String endpoint = request_path;
// the sig string to sign in the form "endpoint|key1=value1|key2=value2|...."
String signature_base_string = generateSignatureBaseString(endpoint, allParamsMap);
String oauth_signature;
try {
oauth_signature = computeSignature(signature_base_string, oAuthConfiguration.getClientSecret());
} catch (GeneralSecurityException ex) {
LOGGER.warn("GeneralSecurityException", ex);
return null;
} catch (UnsupportedEncodingException ex) {
LOGGER.warn("UnsupportedEncodingException", ex);
return null;
}
return oauth_signature;
}
/**
* generateSignatureBaseString.
* @param endpoint endpoint
* @param allParamsMap allParamsMap
* @return String
*/
public static String generateSignatureBaseString(String endpoint, Map<String, String> allParamsMap) {
SortedSet<String> sortedKeys = new TreeSet<>(allParamsMap.keySet());
StringJoiner stringJoiner = new StringJoiner("|");
stringJoiner.add(endpoint);
for ( String key : sortedKeys ) {
stringJoiner.add(key + "=" + allParamsMap.get(key));
}
return stringJoiner.toString();
}
/**
* computeSignature.
* @param signature_base_string Signature Base String
* @param clientSecret Client Secret
* @return String
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws UnsupportedEncodingException
*/
public static String computeSignature(String signature_base_string, String clientSecret) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
SecretKeySpec keySpec = new SecretKeySpec(clientSecret.getBytes(oauth_signature_encoding), oauth_signature_method);
Mac mac = Mac.getInstance(oauth_signature_method);
mac.init(keySpec);
byte[] result = mac.doFinal(signature_base_string.getBytes(oauth_signature_encoding));
return Hex.encodeHexString(result);
}
}