Add recaptcha
This commit is contained in:
1 parent
550d3735c7
commit
2c3fa31e91
29 files changed
+1591
-519
No files matched your search
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2017 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache 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.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.hippo.network;
|
||||
|
||||
/*
|
||||
* Created by Hippo on 2017/9/4.
|
||||
*/
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.database.sqlite.SQLiteStatement;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import com.hippo.database.MSQLiteBuilder;
|
||||
import com.hippo.util.SqlUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import okhttp3.Cookie;
|
||||
|
||||
class CookieDatabase {
|
||||
|
||||
private static final String LOG_TAG = CookieDatabase.class.getSimpleName();
|
||||
|
||||
private static final int VERSION_1 = 1;
|
||||
private static final String TABLE_COOKIE = "OK_HTTP_3_COOKIE";
|
||||
private static final String COLUMN_ID = "_id";
|
||||
private static final String COLUMN_NAME = "NAME";
|
||||
private static final String COLUMN_VALUE = "VALUE";
|
||||
private static final String COLUMN_EXPIRES_AT = "EXPIRES_AT";
|
||||
private static final String COLUMN_DOMAIN = "DOMAIN";
|
||||
private static final String COLUMN_PATH = "PATH";
|
||||
private static final String COLUMN_SECURE = "SECURE";
|
||||
private static final String COLUMN_HTTP_ONLY = "HTTP_ONLY";
|
||||
private static final String COLUMN_PERSISTENT = "PERSISTENT";
|
||||
private static final String COLUMN_HOST_ONLY = "HOST_ONLY";
|
||||
|
||||
private static final int DB_VERSION = VERSION_1;
|
||||
|
||||
private final Map<Cookie, Long> cookieIdMap = new HashMap<>();
|
||||
private final SQLiteOpenHelper helper;
|
||||
private final SQLiteDatabase db;
|
||||
|
||||
public CookieDatabase(Context context, String name) {
|
||||
helper = new MSQLiteBuilder()
|
||||
.version(VERSION_1)
|
||||
.createTable(TABLE_COOKIE)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_NAME, String.class)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_VALUE, String.class)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_EXPIRES_AT, long.class)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_DOMAIN, String.class)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_PATH, String.class)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_SECURE, boolean.class)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_HTTP_ONLY, boolean.class)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_PERSISTENT, boolean.class)
|
||||
.insertColumn(TABLE_COOKIE, COLUMN_HOST_ONLY, boolean.class)
|
||||
.build(context, name, DB_VERSION);
|
||||
db = helper.getWritableDatabase();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Cookie getCookie(Cursor cursor, long now) {
|
||||
String name = SqlUtils.getString(cursor, COLUMN_NAME, null);
|
||||
String value = SqlUtils.getString(cursor, COLUMN_VALUE, null);
|
||||
long expiresAt = SqlUtils.getLong(cursor, COLUMN_EXPIRES_AT, 0);
|
||||
String domain = SqlUtils.getString(cursor, COLUMN_DOMAIN, null);
|
||||
String path = SqlUtils.getString(cursor, COLUMN_PATH, null);
|
||||
boolean secure = SqlUtils.getBoolean(cursor, COLUMN_SECURE, false);
|
||||
boolean httpOnly = SqlUtils.getBoolean(cursor, COLUMN_HTTP_ONLY, false);
|
||||
boolean persistent = SqlUtils.getBoolean(cursor, COLUMN_PERSISTENT, false);
|
||||
boolean hostOnly = SqlUtils.getBoolean(cursor, COLUMN_HOST_ONLY, false);
|
||||
|
||||
if (name == null || domain == null || path == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check non-persistent or expired
|
||||
if (!persistent || expiresAt <= now) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Cookie.Builder builder = new Cookie.Builder();
|
||||
builder.name(name);
|
||||
builder.value(value);
|
||||
if (hostOnly) {
|
||||
builder.hostOnlyDomain(domain);
|
||||
} else {
|
||||
builder.domain(domain);
|
||||
}
|
||||
builder.path(path);
|
||||
builder.expiresAt(expiresAt);
|
||||
if (secure) builder.secure();
|
||||
if (httpOnly) builder.httpOnly();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public Map<String, CookieSet> getAllCookies() {
|
||||
long now = System.currentTimeMillis();
|
||||
Map<String, CookieSet> map = new HashMap<>();
|
||||
List<Long> toRemove = new ArrayList<>();
|
||||
|
||||
Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_COOKIE + ";", null);
|
||||
try {
|
||||
while (cursor.moveToNext()) {
|
||||
long id = SqlUtils.getLong(cursor, COLUMN_ID, 0);
|
||||
Cookie cookie = getCookie(cursor, now);
|
||||
|
||||
if (cookie != null) {
|
||||
// Save id of the cookie in db
|
||||
cookieIdMap.put(cookie, id);
|
||||
|
||||
// Put cookie to set
|
||||
CookieSet set = map.get(cookie.domain());
|
||||
if (set == null) {
|
||||
set = new CookieSet();
|
||||
map.put(cookie.domain(), set);
|
||||
}
|
||||
set.add(cookie);
|
||||
} else {
|
||||
// Mark to remove the cookie
|
||||
toRemove.add(id);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// Remove invalid or expired cookie
|
||||
if (!toRemove.isEmpty()) {
|
||||
SQLiteStatement statement = db.compileStatement(
|
||||
"DELETE FROM " + TABLE_COOKIE + " WHERE " + COLUMN_ID + " = ?;");
|
||||
db.beginTransaction();
|
||||
try {
|
||||
for (long id : toRemove) {
|
||||
statement.bindLong(1, id);
|
||||
statement.executeUpdateDelete();
|
||||
}
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public ContentValues toContentValues(Cookie cookie) {
|
||||
ContentValues contentValues = new ContentValues(9);
|
||||
contentValues.put(COLUMN_NAME, cookie.name());
|
||||
contentValues.put(COLUMN_VALUE, cookie.value());
|
||||
contentValues.put(COLUMN_EXPIRES_AT, cookie.expiresAt());
|
||||
contentValues.put(COLUMN_DOMAIN, cookie.domain());
|
||||
contentValues.put(COLUMN_PATH, cookie.path());
|
||||
contentValues.put(COLUMN_SECURE, cookie.secure());
|
||||
contentValues.put(COLUMN_HTTP_ONLY, cookie.httpOnly());
|
||||
contentValues.put(COLUMN_PERSISTENT, cookie.persistent());
|
||||
contentValues.put(COLUMN_HOST_ONLY, cookie.hostOnly());
|
||||
return contentValues;
|
||||
}
|
||||
|
||||
public void add(Cookie cookie) {
|
||||
long id = db.insert(TABLE_COOKIE, null, toContentValues(cookie));
|
||||
if (id != -1L) {
|
||||
Long oldId = cookieIdMap.put(cookie, id);
|
||||
if (oldId != null) Log.e(LOG_TAG, "Add a duplicate cookie");
|
||||
} else {
|
||||
Log.e(LOG_TAG, "An error occurred when insert a cookie");
|
||||
}
|
||||
}
|
||||
|
||||
public void update(Cookie from, Cookie to) {
|
||||
Long id = cookieIdMap.get(from);
|
||||
if (id == null) {
|
||||
Log.e(LOG_TAG, "Can't get id when update the cookie");
|
||||
return;
|
||||
}
|
||||
|
||||
ContentValues values = toContentValues(to);
|
||||
String whereClause = COLUMN_ID + " = ?";
|
||||
String[] whereArgs = { id.toString() };
|
||||
int count = db.update(TABLE_COOKIE, values, whereClause, whereArgs);
|
||||
if (count != 1) {
|
||||
Log.e(LOG_TAG, "Bad result when update cookie: " + count);
|
||||
}
|
||||
|
||||
// Update it in cookie-id map
|
||||
cookieIdMap.remove(from);
|
||||
cookieIdMap.put(to, id);
|
||||
}
|
||||
|
||||
public void remove(Cookie cookie) {
|
||||
Long id = cookieIdMap.get(cookie);
|
||||
if (id == null) {
|
||||
Log.e(LOG_TAG, "Can't get id when remove the cookie");
|
||||
return;
|
||||
}
|
||||
|
||||
String whereClause = COLUMN_ID + " = ?";
|
||||
String[] whereArgs = { id.toString() };
|
||||
int count = db.delete(TABLE_COOKIE, whereClause, whereArgs);
|
||||
if (count != 1) {
|
||||
Log.e(LOG_TAG, "Bad result when remove cookie: " + count);
|
||||
}
|
||||
|
||||
// Remove it from cookie-id map
|
||||
cookieIdMap.remove(cookie);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
db.delete(TABLE_COOKIE, null, null);
|
||||
cookieIdMap.clear();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
db.close();
|
||||
helper.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright 2017 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache 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.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.hippo.network;
|
||||
|
||||
/*
|
||||
* Created by Hippo on 2017/9/4.
|
||||
*/
|
||||
|
||||
import android.content.Context;
|
||||
import com.hippo.yorozuya.ObjectUtils;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.CookieJar;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.Request;
|
||||
|
||||
public class CookieRepository implements CookieJar {
|
||||
|
||||
private CookieDatabase db;
|
||||
private Map<String, CookieSet> map;
|
||||
|
||||
public CookieRepository(Context context, String name) {
|
||||
db = new CookieDatabase(context, name);
|
||||
map = db.getAllCookies();
|
||||
}
|
||||
|
||||
public synchronized void addCookie(Cookie cookie) {
|
||||
// For cookie database
|
||||
Cookie toAdd = null;
|
||||
Cookie toUpdate = null;
|
||||
Cookie toRemove = null;
|
||||
|
||||
CookieSet set = map.get(cookie.domain());
|
||||
if (set == null) {
|
||||
set = new CookieSet();
|
||||
map.put(cookie.domain(), set);
|
||||
}
|
||||
|
||||
if (cookie.expiresAt() <= System.currentTimeMillis()) {
|
||||
toRemove = set.remove(cookie);
|
||||
// If the cookie is not persistent, it's not in database
|
||||
if (toRemove != null && !toRemove.persistent()) {
|
||||
toRemove = null;
|
||||
}
|
||||
} else {
|
||||
toAdd = cookie;
|
||||
toUpdate = set.add(cookie);
|
||||
// If the cookie is not persistent, it's not in database
|
||||
if (!toAdd.persistent()) toAdd = null;
|
||||
if (toUpdate != null && !toUpdate.persistent()) toUpdate = null;
|
||||
// Remove the cookie if it updates to null
|
||||
if (toAdd == null && toUpdate != null) {
|
||||
toRemove = toUpdate;
|
||||
toUpdate = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (toRemove != null) {
|
||||
db.remove(toRemove);
|
||||
}
|
||||
if (toAdd != null) {
|
||||
if (toUpdate != null) {
|
||||
db.update(toUpdate, toAdd);
|
||||
} else {
|
||||
db.add(toAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized List<Cookie> getCookies(HttpUrl url) {
|
||||
List<Cookie> accepted = new ArrayList<>();
|
||||
List<Cookie> expired = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, CookieSet> entry : map.entrySet()) {
|
||||
String domain = entry.getKey();
|
||||
CookieSet cookieSet = entry.getValue();
|
||||
if (domainMatch(url, domain)) {
|
||||
cookieSet.get(url, accepted, expired);
|
||||
}
|
||||
}
|
||||
|
||||
for (Cookie cookie : expired) {
|
||||
if (cookie.persistent()) {
|
||||
db.remove(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
// RFC 6265 Section-5.4 step 2, sort the cookie-list
|
||||
// Cookies with longer paths are listed before cookies with shorter paths.
|
||||
// Ignore creation-time, we don't store them.
|
||||
Collections.sort(accepted, new Comparator<Cookie>() {
|
||||
@Override
|
||||
public int compare(Cookie o1, Cookie o2) {
|
||||
return o2.path().length() - o1.path().length();
|
||||
}
|
||||
});
|
||||
|
||||
return accepted;
|
||||
}
|
||||
|
||||
public boolean contains(HttpUrl url, String name) {
|
||||
for (Cookie cookie : getCookies(url)) {
|
||||
if (ObjectUtils.equal(cookie.name(), name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all cookies in this {@code CookieRepository}.
|
||||
*/
|
||||
public synchronized void clear() {
|
||||
map.clear();
|
||||
db.clear();
|
||||
}
|
||||
|
||||
public synchronized void close() {
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
|
||||
for (Cookie cookie : list) {
|
||||
addCookie(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cookie> loadForRequest(HttpUrl httpUrl, Request request) {
|
||||
return getCookies(httpUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick and dirty pattern to differentiate IP addresses from hostnames. This is an approximation
|
||||
* of Android's private InetAddress#isNumeric API.
|
||||
*
|
||||
* This matches IPv6 addresses as a hex string containing at least one colon, and possibly
|
||||
* including dots after the first colon. It matches IPv4 addresses as strings containing only
|
||||
* decimal digits and dots. This pattern matches strings like "a:.23" and "54" that are neither IP
|
||||
* addresses nor hostnames; they will be verified as IP addresses (which is a more strict
|
||||
* verification).
|
||||
*/
|
||||
private static final Pattern VERIFY_AS_IP_ADDRESS = Pattern.compile("([0-9a-fA-F]*:[0-9a-fA-F:.]*)|([\\d.]+)");
|
||||
|
||||
/**
|
||||
* Returns true if `host` is not a host name and might be an IP address.
|
||||
*/
|
||||
private static boolean verifyAsIpAddress(String host) {
|
||||
return VERIFY_AS_IP_ADDRESS.matcher(host).matches();
|
||||
}
|
||||
|
||||
// okhttp3.Cookie.domainMatch(HttpUrl, String)
|
||||
protected static boolean domainMatch(HttpUrl url, String domain) {
|
||||
String urlHost = url.host();
|
||||
|
||||
if (urlHost.equals(domain)) {
|
||||
return true; // As in 'example.com' matching 'example.com'.
|
||||
}
|
||||
|
||||
if (urlHost.endsWith(domain)
|
||||
&& urlHost.charAt(urlHost.length() - domain.length() - 1) == '.'
|
||||
&& !verifyAsIpAddress(urlHost)) {
|
||||
return true; // As in 'example.com' matching 'www.example.com'.
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2017 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache 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.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.hippo.network;
|
||||
|
||||
/*
|
||||
* Created by Hippo on 2017/9/4.
|
||||
*/
|
||||
|
||||
import com.hippo.util.HashCodeUtils;
|
||||
import com.hippo.yorozuya.ObjectUtils;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
class CookieSet {
|
||||
|
||||
private Map<Key, Cookie> map = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Adds a cookie to this {@code CookieSet}.
|
||||
* Returns a previous cookie with
|
||||
* the same name, domain and path or {@code null}.
|
||||
*/
|
||||
public Cookie add(Cookie cookie) {
|
||||
return map.put(new Key(cookie), cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a cookie with the same name,
|
||||
* domain and path as the cookie.
|
||||
* Returns the removed cookie or {@code null}.
|
||||
*/
|
||||
public Cookie remove(Cookie cookie) {
|
||||
return map.remove(new Key(cookie));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cookies for the url. Fill {@code accepted} and {@code expired}.
|
||||
*/
|
||||
public void get(HttpUrl url, List<Cookie> accepted, List<Cookie> expired) {
|
||||
long now = System.currentTimeMillis();
|
||||
Iterator<Map.Entry<Key, Cookie>> iterator = map.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Cookie cookie = iterator.next().getValue();
|
||||
if (cookie.expiresAt() <= now) {
|
||||
iterator.remove();
|
||||
expired.add(cookie);
|
||||
} else if (cookie.matches(url)) {
|
||||
accepted.add(cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class Key {
|
||||
|
||||
private String name;
|
||||
private String domain;
|
||||
private String path;
|
||||
|
||||
public Key(Cookie cookie) {
|
||||
this.name = cookie.name();
|
||||
this.domain = cookie.domain();
|
||||
this.path = cookie.path();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof Key) {
|
||||
Key key = (Key) obj;
|
||||
return ObjectUtils.equal(key.name, this.name) &&
|
||||
ObjectUtils.equal(key.domain, this.domain) &&
|
||||
ObjectUtils.equal(key.path, this.path);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeUtils.hashCode(name, domain, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user