Austin Huang
4 years ago
No known key found for this signature in database
GPG Key ID: 84C23AA04587A91F
3 changed files with 104 additions and 220 deletions
-
89app/src/main/java/awais/instagrabber/utils/PasswordUtils.kt
-
161app/src/main/java/awais/instagrabber/utils/TextUtils.kt
-
74app/src/main/java/awais/instagrabber/utils/UrlEncoder.java
@ -1,47 +1,52 @@ |
|||||
package awais.instagrabber.utils; |
|
||||
|
|
||||
import android.util.Base64; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import java.security.GeneralSecurityException; |
|
||||
import java.security.InvalidAlgorithmParameterException; |
|
||||
import java.security.InvalidKeyException; |
|
||||
import java.security.NoSuchAlgorithmException; |
|
||||
|
|
||||
import javax.crypto.BadPaddingException; |
|
||||
import javax.crypto.Cipher; |
|
||||
import javax.crypto.IllegalBlockSizeException; |
|
||||
import javax.crypto.NoSuchPaddingException; |
|
||||
import javax.crypto.spec.IvParameterSpec; |
|
||||
import javax.crypto.spec.SecretKeySpec; |
|
||||
|
|
||||
public final class PasswordUtils { |
|
||||
private static final String cipherAlgo = "AES"; |
|
||||
private static final String cipherTran = "AES/CBC/PKCS5Padding"; |
|
||||
|
|
||||
public static byte[] dec(final String encrypted, final byte[] keyValue) throws Exception { |
|
||||
try { |
|
||||
final Cipher cipher = Cipher.getInstance(cipherTran); |
|
||||
final SecretKeySpec secretKey = new SecretKeySpec(keyValue, cipherAlgo); |
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new byte[16])); |
|
||||
return cipher.doFinal(Base64.decode(encrypted, Base64.DEFAULT | Base64.NO_PADDING | Base64.NO_WRAP)); |
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) { |
|
||||
throw new IncorrectPasswordException(e); |
|
||||
|
package awais.instagrabber.utils |
||||
|
|
||||
|
import android.util.Base64 |
||||
|
import java.security.GeneralSecurityException |
||||
|
import java.security.InvalidAlgorithmParameterException |
||||
|
import java.security.InvalidKeyException |
||||
|
import java.security.NoSuchAlgorithmException |
||||
|
import javax.crypto.BadPaddingException |
||||
|
import javax.crypto.Cipher |
||||
|
import javax.crypto.IllegalBlockSizeException |
||||
|
import javax.crypto.NoSuchPaddingException |
||||
|
import javax.crypto.spec.IvParameterSpec |
||||
|
import javax.crypto.spec.SecretKeySpec |
||||
|
|
||||
|
object PasswordUtils { |
||||
|
private const val cipherAlgo = "AES" |
||||
|
private const val cipherTran = "AES/CBC/PKCS5Padding" |
||||
|
@JvmStatic |
||||
|
@Throws(Exception::class) |
||||
|
fun dec(encrypted: String?, keyValue: ByteArray?): ByteArray { |
||||
|
return try { |
||||
|
val cipher = Cipher.getInstance(cipherTran) |
||||
|
val secretKey = SecretKeySpec(keyValue, cipherAlgo) |
||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(ByteArray(16))) |
||||
|
cipher.doFinal(Base64.decode(encrypted, Base64.DEFAULT or Base64.NO_PADDING or Base64.NO_WRAP)) |
||||
|
} catch (e: NoSuchAlgorithmException) { |
||||
|
throw IncorrectPasswordException(e) |
||||
|
} catch (e: NoSuchPaddingException) { |
||||
|
throw IncorrectPasswordException(e) |
||||
|
} catch (e: InvalidAlgorithmParameterException) { |
||||
|
throw IncorrectPasswordException(e) |
||||
|
} catch (e: InvalidKeyException) { |
||||
|
throw IncorrectPasswordException(e) |
||||
|
} catch (e: BadPaddingException) { |
||||
|
throw IncorrectPasswordException(e) |
||||
|
} catch (e: IllegalBlockSizeException) { |
||||
|
throw IncorrectPasswordException(e) |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
public static byte[] enc(@NonNull final String str, final byte[] keyValue) throws Exception { |
|
||||
final Cipher cipher = Cipher.getInstance(cipherTran); |
|
||||
final SecretKeySpec secretKey = new SecretKeySpec(keyValue, cipherAlgo); |
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new byte[16])); |
|
||||
final byte[] bytes = cipher.doFinal(str.getBytes()); |
|
||||
return Base64.encode(bytes, Base64.DEFAULT | Base64.NO_PADDING | Base64.NO_WRAP); |
|
||||
|
@JvmStatic |
||||
|
@Throws(Exception::class) |
||||
|
fun enc(str: String, keyValue: ByteArray?): ByteArray { |
||||
|
val cipher = Cipher.getInstance(cipherTran) |
||||
|
val secretKey = SecretKeySpec(keyValue, cipherAlgo) |
||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey, IvParameterSpec(ByteArray(16))) |
||||
|
val bytes = cipher.doFinal(str.toByteArray()) |
||||
|
return Base64.encode(bytes, Base64.DEFAULT or Base64.NO_PADDING or Base64.NO_WRAP) |
||||
} |
} |
||||
|
|
||||
public static class IncorrectPasswordException extends Exception { |
|
||||
public IncorrectPasswordException(final GeneralSecurityException e) { |
|
||||
super(e); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
class IncorrectPasswordException(e: GeneralSecurityException?) : Exception(e) |
||||
|
} |
@ -1,122 +1,75 @@ |
|||||
package awais.instagrabber.utils; |
|
||||
|
|
||||
import android.content.Context; |
|
||||
import android.text.SpannableString; |
|
||||
import android.text.format.DateFormat; |
|
||||
import android.text.format.DateUtils; |
|
||||
import android.text.style.URLSpan; |
|
||||
import android.util.Patterns; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import java.util.ArrayList; |
|
||||
import java.util.Arrays; |
|
||||
import java.util.Collections; |
|
||||
import java.util.Date; |
|
||||
import java.util.List; |
|
||||
import java.util.Locale; |
|
||||
import java.util.regex.Matcher; |
|
||||
import java.util.stream.Collectors; |
|
||||
|
|
||||
public final class TextUtils { |
|
||||
// extracted from String class |
|
||||
public static int indexOfChar(@NonNull final CharSequence sequence, final int ch, final int startIndex) { |
|
||||
final int max = sequence.length(); |
|
||||
if (startIndex < max) { |
|
||||
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) { |
|
||||
for (int i = startIndex; i < max; i++) if (sequence.charAt(i) == ch) return i; |
|
||||
} else if (Character.isValidCodePoint(ch)) { |
|
||||
final char hi = (char) ((ch >>> 10) + (Character.MIN_HIGH_SURROGATE - (Character.MIN_SUPPLEMENTARY_CODE_POINT >>> 10))); |
|
||||
final char lo = (char) ((ch & 0x3ff) + Character.MIN_LOW_SURROGATE); |
|
||||
for (int i = startIndex; i < max; i++) |
|
||||
if (sequence.charAt(i) == hi && sequence.charAt(i + 1) == lo) return i; |
|
||||
} |
|
||||
|
package awais.instagrabber.utils |
||||
|
|
||||
|
import android.content.Context |
||||
|
import android.text.format.DateFormat |
||||
|
import android.text.format.DateUtils |
||||
|
import android.util.Patterns |
||||
|
import java.util.* |
||||
|
|
||||
|
object TextUtils { |
||||
|
@JvmStatic |
||||
|
fun isEmpty(charSequence: CharSequence?): Boolean { |
||||
|
if (charSequence == null || charSequence.length < 1) return true |
||||
|
if (charSequence is String) { |
||||
|
var str = charSequence |
||||
|
if ("" == str || "null" == str || str.isEmpty()) return true |
||||
|
str = str.trim { it <= ' ' } |
||||
|
return "" == str || "null" == str || str.isEmpty() |
||||
} |
} |
||||
return -1; |
|
||||
|
return "null".contentEquals(charSequence) || "".contentEquals(charSequence) |
||||
} |
} |
||||
|
|
||||
public static CharSequence getSpannableUrl(final String url) { |
|
||||
if (isEmpty(url)) return url; |
|
||||
final int httpIndex = url.indexOf("http:"); |
|
||||
final int httpsIndex = url.indexOf("https:"); |
|
||||
if (httpIndex == -1 && httpsIndex == -1) return url; |
|
||||
|
|
||||
final int length = url.length(); |
|
||||
|
|
||||
final int startIndex = httpIndex != -1 ? httpIndex : httpsIndex; |
|
||||
final int spaceIndex = url.indexOf(' ', startIndex + 1); |
|
||||
|
|
||||
final int endIndex = (spaceIndex != -1 ? spaceIndex : length); |
|
||||
|
|
||||
final String extractUrl = url.substring(startIndex, Math.min(length, endIndex)); |
|
||||
|
|
||||
final SpannableString spannableString = new SpannableString(url); |
|
||||
spannableString.setSpan(new URLSpan(extractUrl), startIndex, endIndex, 0); |
|
||||
|
|
||||
return spannableString; |
|
||||
} |
|
||||
|
|
||||
public static boolean isEmpty(final CharSequence charSequence) { |
|
||||
if (charSequence == null || charSequence.length() < 1) return true; |
|
||||
if (charSequence instanceof String) { |
|
||||
String str = (String) charSequence; |
|
||||
if ("".equals(str) || "null".equals(str) || str.isEmpty()) return true; |
|
||||
str = str.trim(); |
|
||||
return "".equals(str) || "null".equals(str) || str.isEmpty(); |
|
||||
} |
|
||||
return "null".contentEquals(charSequence) || "".contentEquals(charSequence); |
|
||||
} |
|
||||
|
|
||||
public static String millisToTimeString(final long millis) { |
|
||||
return millisToTimeString(millis, false); |
|
||||
} |
|
||||
|
|
||||
public static String millisToTimeString(final long millis, final boolean includeHoursAlways) { |
|
||||
final int sec = (int) (millis / 1000) % 60; |
|
||||
int min = (int) (millis / (1000 * 60)); |
|
||||
|
@JvmStatic |
||||
|
@JvmOverloads |
||||
|
fun millisToTimeString(millis: Long, includeHoursAlways: Boolean = false): String { |
||||
|
val sec = (millis / 1000).toInt() % 60 |
||||
|
var min = (millis / (1000 * 60)).toInt() |
||||
if (min >= 60) { |
if (min >= 60) { |
||||
min = (int) ((millis / (1000 * 60)) % 60); |
|
||||
final int hr = (int) ((millis / (1000 * 60 * 60)) % 24); |
|
||||
return String.format(Locale.ENGLISH, "%02d:%02d:%02d", hr, min, sec); |
|
||||
|
min = (millis / (1000 * 60) % 60).toInt() |
||||
|
val hr = (millis / (1000 * 60 * 60) % 24).toInt() |
||||
|
return String.format(Locale.ENGLISH, "%02d:%02d:%02d", hr, min, sec) |
||||
} |
} |
||||
if (includeHoursAlways) { |
|
||||
return String.format(Locale.ENGLISH, "%02d:%02d:%02d", 0, min, sec); |
|
||||
} |
|
||||
return String.format(Locale.ENGLISH, "%02d:%02d", min, sec); |
|
||||
|
return if (includeHoursAlways) { |
||||
|
String.format(Locale.ENGLISH, "%02d:%02d:%02d", 0, min, sec) |
||||
|
} else String.format(Locale.ENGLISH, "%02d:%02d", min, sec) |
||||
} |
} |
||||
|
|
||||
public static String getRelativeDateTimeString(final Context context, final long from) { |
|
||||
final Date now = new Date(); |
|
||||
final Date then = new Date(from); |
|
||||
int days = daysBetween(from, now.getTime()); |
|
||||
if (days == 0) { |
|
||||
return DateFormat.getTimeFormat(context).format(then); |
|
||||
} |
|
||||
return DateFormat.getDateFormat(context).format(then); |
|
||||
|
@JvmStatic |
||||
|
fun getRelativeDateTimeString(context: Context?, from: Long): String { |
||||
|
val now = Date() |
||||
|
val then = Date(from) |
||||
|
val days = daysBetween(from, now.time) |
||||
|
return if (days == 0) { |
||||
|
DateFormat.getTimeFormat(context).format(then) |
||||
|
} else DateFormat.getDateFormat(context).format(then) |
||||
} |
} |
||||
|
|
||||
private static int daysBetween(long d1, long d2) { |
|
||||
return (int) ((d2 - d1) / DateUtils.DAY_IN_MILLIS); |
|
||||
|
private fun daysBetween(d1: Long, d2: Long): Int { |
||||
|
return ((d2 - d1) / DateUtils.DAY_IN_MILLIS).toInt() |
||||
} |
} |
||||
|
|
||||
public static List<String> extractUrls(final String text) { |
|
||||
if (isEmpty(text)) return Collections.emptyList(); |
|
||||
final Matcher matcher = Patterns.WEB_URL.matcher(text); |
|
||||
final List<String> urls = new ArrayList<>(); |
|
||||
|
@JvmStatic |
||||
|
fun extractUrls(text: String?): List<String> { |
||||
|
if (isEmpty(text)) return emptyList() |
||||
|
val matcher = Patterns.WEB_URL.matcher(text) |
||||
|
val urls: MutableList<String> = ArrayList() |
||||
while (matcher.find()) { |
while (matcher.find()) { |
||||
urls.add(matcher.group()); |
|
||||
|
urls.add(matcher.group()) |
||||
} |
} |
||||
return urls; |
|
||||
|
return urls |
||||
} |
} |
||||
|
|
||||
// https://github.com/notslang/instagram-id-to-url-segment |
// https://github.com/notslang/instagram-id-to-url-segment |
||||
public static long shortcodeToId(final String shortcode) { |
|
||||
long result = 0L; |
|
||||
for (int i = 0; i < shortcode.length() && i < 11; i++){ |
|
||||
final char c = shortcode.charAt(i); |
|
||||
final int k = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(c); |
|
||||
result = result * 64 + k; |
|
||||
|
@JvmStatic |
||||
|
fun shortcodeToId(shortcode: String): Long { |
||||
|
var result = 0L |
||||
|
var i = 0 |
||||
|
while (i < shortcode.length && i < 11) { |
||||
|
val c = shortcode[i] |
||||
|
val k = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".indexOf(c) |
||||
|
result = result * 64 + k |
||||
|
i++ |
||||
} |
} |
||||
return result; |
|
||||
|
return result |
||||
} |
} |
||||
} |
|
||||
|
} |
@ -1,74 +0,0 @@ |
|||||
package awais.instagrabber.utils; |
|
||||
|
|
||||
import androidx.annotation.NonNull; |
|
||||
|
|
||||
import java.io.CharArrayWriter; |
|
||||
import java.util.BitSet; |
|
||||
|
|
||||
// same as java.net.URLEncoder |
|
||||
public final class UrlEncoder { |
|
||||
private static final BitSet dontNeedEncoding = new BitSet(256); |
|
||||
private static final int caseDiff = ('a' - 'A'); |
|
||||
|
|
||||
static { |
|
||||
int i; |
|
||||
for (i = 'a'; i <= 'z'; i++) dontNeedEncoding.set(i); |
|
||||
for (i = 'A'; i <= 'Z'; i++) dontNeedEncoding.set(i); |
|
||||
for (i = '0'; i <= '9'; i++) dontNeedEncoding.set(i); |
|
||||
dontNeedEncoding.set(' '); |
|
||||
dontNeedEncoding.set('-'); |
|
||||
dontNeedEncoding.set('_'); |
|
||||
dontNeedEncoding.set('.'); |
|
||||
dontNeedEncoding.set('*'); |
|
||||
} |
|
||||
|
|
||||
@NonNull |
|
||||
public static String encodeUrl(@NonNull final String s) { |
|
||||
final StringBuilder out = new StringBuilder(s.length()); |
|
||||
final CharArrayWriter charArrayWriter = new CharArrayWriter(); |
|
||||
|
|
||||
boolean needToChange = false; |
|
||||
for (int i = 0; i < s.length(); ) { |
|
||||
int c = s.charAt(i); |
|
||||
|
|
||||
if (dontNeedEncoding.get(c)) { |
|
||||
if (c == ' ') { |
|
||||
c = '+'; |
|
||||
needToChange = true; |
|
||||
} |
|
||||
|
|
||||
out.append((char) c); |
|
||||
i++; |
|
||||
} else { |
|
||||
do { |
|
||||
charArrayWriter.write(c); |
|
||||
if (c >= 0xD800 && c <= 0xDBFF && i + 1 < s.length()) { |
|
||||
final int d = s.charAt(i + 1); |
|
||||
if (d >= 0xDC00 && d <= 0xDFFF) { |
|
||||
charArrayWriter.write(d); |
|
||||
i++; |
|
||||
} |
|
||||
} |
|
||||
i++; |
|
||||
} while (i < s.length() && !dontNeedEncoding.get(c = s.charAt(i))); |
|
||||
|
|
||||
charArrayWriter.flush(); |
|
||||
|
|
||||
final byte[] ba = charArrayWriter.toString().getBytes(); |
|
||||
for (final byte b : ba) { |
|
||||
out.append('%'); |
|
||||
char ch = Character.forDigit((b >> 4) & 0xF, 16); |
|
||||
if (Character.isLetter(ch)) ch -= caseDiff; |
|
||||
out.append(ch); |
|
||||
ch = Character.forDigit(b & 0xF, 16); |
|
||||
if (Character.isLetter(ch)) ch -= caseDiff; |
|
||||
out.append(ch); |
|
||||
} |
|
||||
charArrayWriter.reset(); |
|
||||
needToChange = true; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return (needToChange ? out.toString() : s); |
|
||||
} |
|
||||
} |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue