/*
* Copyright 2011 Sina.
*
* Licensed under the Apache License and Weibo License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.open.weibo.com
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.joyplus.joylink.weibo.net;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Random;
import android.os.Bundle;
/**
* Encapsulation a abstract weibo http headers base class.
*
* @author ZhangJie (zhangjie2@staff.sina.com.cn)
*/
public abstract class HttpHeaderFactory {
public static final String CONST_HMAC_SHA1 = "HmacSHA1";
public static final String CONST_SIGNATURE_METHOD = "HMAC-SHA1";
public static final String CONST_OAUTH_VERSION = "1.0";
public HttpHeaderFactory() {
}
public String getWeiboAuthHeader(String method, String url, WeiboParameters params,
String app_key, String app_secret, Token token) throws WeiboException {
// step 1: generate timestamp and nonce
final long timestamp = System.currentTimeMillis() / 1000;
final long nonce = timestamp + (new Random()).nextInt();
// step 2: authParams有两个用处:1.加密串一部分 2.生成最后Authorization头域
WeiboParameters authParams = this.generateAuthParameters(nonce, timestamp, token);
// 生成用于计算signature的,参数串
WeiboParameters signatureParams = this.generateSignatureParameters(authParams, params, url);
// step 3: 生成用于签名的base String
String oauthBaseString = this.generateAuthSignature(method, signatureParams, url, token);
// step 4: 生成oauth_signature
String signature = generateSignature(oauthBaseString, token);
authParams.add("oauth_signature", signature);
// step 5: for additional parameters
this.addAdditionalParams(authParams, params);
return "OAuth " + encodeParameters(authParams, ",", true);
}
private String generateAuthSignature(final String method, WeiboParameters signatureParams,
final String url, Token token) {
StringBuffer base = new StringBuffer(method).append("&")
.append(encode(constructRequestURL(url))).append("&");
base.append(encode(encodeParameters(signatureParams, "&", false)));
String oauthBaseString = base.toString();
return oauthBaseString;
}
private WeiboParameters generateSignatureParameters(WeiboParameters authParams,
WeiboParameters params, String url) throws WeiboException {
WeiboParameters signatureParams = new WeiboParameters();
signatureParams.addAll(authParams);
signatureParams.add("source", Weibo.getAppKey());
signatureParams.addAll(params);
this.parseUrlParameters(url, signatureParams);
WeiboParameters lsp = generateSignatureList(signatureParams);
return lsp;
}
private WeiboParameters generateAuthParameters(long nonce, long timestamp, Token token) {
WeiboParameters authParams = new WeiboParameters();
authParams.add("oauth_consumer_key", Weibo.getAppKey());
authParams.add("oauth_nonce", String.valueOf(nonce));
authParams.add("oauth_signature_method", HttpHeaderFactory.CONST_SIGNATURE_METHOD);
authParams.add("oauth_timestamp", String.valueOf(timestamp));
authParams.add("oauth_version", HttpHeaderFactory.CONST_OAUTH_VERSION);
if (token != null) {
authParams.add("oauth_token", token.getToken());
} else {
authParams.add("source", Weibo.getAppKey());
}
return authParams;
}
// 生成用于哈希的base string串,注意要按顺序,按需文档需求参数生成,否则40107错误
public abstract WeiboParameters generateSignatureList(WeiboParameters bundle);
// add additional parameters to des key-value pairs,support to expanding
// params
public abstract void addAdditionalParams(WeiboParameters des, WeiboParameters src);
// 解析url中参数对,存储到signatureBaseParams
public void parseUrlParameters(String url, WeiboParameters signatureBaseParams)
throws WeiboException {
int queryStart = url.indexOf("?");
if (-1 != queryStart) {
String[] queryStrs = url.substring(queryStart + 1).split("&");
try {
for (String query : queryStrs) {
String[] split = query.split("=");
if (split.length == 2) {
signatureBaseParams.add(URLDecoder.decode(split[0], "UTF-8"),
URLDecoder.decode(split[1], "UTF-8"));
} else {
signatureBaseParams.add(URLDecoder.decode(split[0], "UTF-8"), "");
}
}
} catch (UnsupportedEncodingException e) {
throw new WeiboException(e);
}
}
}
public abstract String generateSignature(String data, Token token) throws WeiboException;
public static String encodeParameters(WeiboParameters postParams, String splitter, boolean quot) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < postParams.size(); i++) {
if (buf.length() != 0) {
if (quot) {
buf.append("\"");
}
buf.append(splitter);
}
buf.append(encode(postParams.getKey(i))).append("=");
if (quot) {
buf.append("\"");
}
buf.append(encode(postParams.getValue(i)));
}
if (buf.length() != 0) {
if (quot) {
buf.append("\"");
}
}
return buf.toString();
}
public static String encodeParameters(Bundle postParams, String split, boolean quot) {
final String splitter = split;
StringBuffer buf = new StringBuffer();
for (String key : postParams.keySet()) {
if (buf.length() != 0) {
if (quot) {
buf.append("\"");
}
buf.append(splitter);
}
buf.append(encode(key)).append("=");
if (quot) {
buf.append("\"");
}
buf.append(encode(postParams.getString(key)));
}
if (buf.length() != 0) {
if (quot) {
buf.append("\"");
}
}
return buf.toString();
}
//
public static String constructRequestURL(String url) {
int index = url.indexOf("?");
if (-1 != index) {
url = url.substring(0, index);
}
int slashIndex = url.indexOf("/", 8);
String baseURL = url.substring(0, slashIndex).toLowerCase();
int colonIndex = baseURL.indexOf(":", 8);
if (-1 != colonIndex) {
// url contains port number
if (baseURL.startsWith("http://") && baseURL.endsWith(":80")) {
// http default port 80 MUST be excluded
baseURL = baseURL.substring(0, colonIndex);
} else if (baseURL.startsWith("https://") && baseURL.endsWith(":443")) {
// http default port 443 MUST be excluded
baseURL = baseURL.substring(0, colonIndex);
}
}
url = baseURL + url.substring(slashIndex);
return url;
}
/**
* @param value
* string to be encoded
* @return encoded parameters string
*/
public static String encode(String value) {
String encoded = null;
try {
encoded = URLEncoder.encode(value, "UTF-8");
} catch (UnsupportedEncodingException ignore) {
}
StringBuffer buf = new StringBuffer(encoded.length());
char focus;
for (int i = 0; i < encoded.length(); i++) {
focus = encoded.charAt(i);
if (focus == '*') {
buf.append("%2A");
} else if (focus == '+') {
buf.append("%20");
} else if (focus == '%' && (i + 1) < encoded.length() && encoded.charAt(i + 1) == '7'
&& encoded.charAt(i + 2) == 'E') {
buf.append('~');
i += 2;
} else {
buf.append(focus);
}
}
return buf.toString();
}
}