/* * Overchan Android (Meta Imageboard Client) * Copyright (C) 2014-2016 miku-nyan <https://github.com/miku-nyan> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package nya.miku.wishmaster.api.util; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.graphics.Color; public class CryptoUtils { private CryptoUtils() {} private static final Pattern CF_EMAIL = Pattern.compile("<a class=\"__cf_email__\"(?:.*?)data-cfemail=\"([^\"]*)\"(?:.*?)</script>", Pattern.DOTALL); private static Random random = null; /** * Вычислить MD5 контрольную сумму, представить в виде hex-строки * @param str строка, от которой вычисляется хэш * @return строка с hex-представлением значения MD5 */ public static String computeMD5(String str) { if (str == null) str = ""; try { MessageDigest messageDigest = MessageDigest.getInstance("MD5"); messageDigest.reset(); messageDigest.update(str.getBytes()); byte[] digest = messageDigest.digest(); BigInteger bigInt = new BigInteger(1, digest); String md5Hex = bigInt.toString(16); if (md5Hex.length() < 32){ char[] head = new char[32 - md5Hex.length()]; Arrays.fill(head, '0'); md5Hex = new StringBuilder(32).append(head).append(md5Hex).toString(); } return md5Hex; } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } /** * Вычислить SHA-1 контрольную сумму, представить в виде hex-строки * @param str строка, от которой вычисляется хэш * @return строка с hex-представлением значения SHA-1 */ public static String computeSHA1(String str) { if (str == null) str = ""; try { MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); messageDigest.reset(); messageDigest.update(str.getBytes()); byte[] digest = messageDigest.digest(); BigInteger bigInt = new BigInteger(1, digest); String sha1Hex = bigInt.toString(16); if (sha1Hex.length() < 40){ char[] head = new char[40 - sha1Hex.length()]; Arrays.fill(head, '0'); sha1Hex = new StringBuilder(40).append(head).append(sha1Hex).toString(); } return sha1Hex; } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } /** * Сгенерировать пароль, состоящий из букв латинского алфавита и цифр, длиной от 10 до 15 символов * @return строка с паролем */ public static String genPassword() { if (random == null) random = new Random(); return genPassword(10 + random.nextInt(6)); } /** * Сгенерировать пароль, состоящий из букв латинского алфавита и цифр * @param len длина * @return строка с паролем */ public static String genPassword(int len) { if (random == null) random = new Random(); StringBuilder builder = new StringBuilder(len); for (int i=0; i<len; ++i) { char ch; int c = random.nextInt(62); if (c < 10) { ch = Character.forDigit(c, 10); } else if (c < 36) { c -= 10; ch = (char) ('a' + c); } else { c -= 36; ch = (char) ('A' + c); } builder.append(ch); } return builder.toString(); } /** * Декодировать строку, закодированную Cloudflare Email Protection */ public static String decodeCloudflareEmail(String encoded) { try { StringBuilder sb = new StringBuilder(); int r = Integer.parseInt(encoded.substring(0, 2), 16); for(int n=2; n<encoded.length(); n+=2) { sb.append((char)(Integer.parseInt(encoded.substring(n, n+2), 16) ^ r)); } return sb.toString(); } catch (Exception e) { return encoded; } } /** * Восстановить все адреса E-mail, XMPP и др., закодированные Cloudflare Email Protection в комментарии, * вырезать скрипты и закодированные строки, заменить на обычный (читабельный, не требующий js) текст. * @param commentBody тело комментария (HTML) * @return исправленное тело комментария */ public static String fixCloudflareEmails(String commentBody) { Matcher matcher = CF_EMAIL.matcher(commentBody); if (!matcher.find()) return commentBody; StringBuffer sb = new StringBuffer(); do { String found = matcher.group(1); matcher.appendReplacement(sb, decodeCloudflareEmail(found)); } while (matcher.find()); matcher.appendTail(sb); return sb.toString(); } /** * Получить значение цвета для данного id (строки) */ public static int hashIdColor(String id) { if (id.length() == 6) { try { return Color.rgb( Integer.parseInt(id.substring(0, 2), 16), Integer.parseInt(id.substring(2, 4), 16), Integer.parseInt(id.substring(4), 16)); } catch (Exception e) {} } Random random = new Random(id.hashCode()); return Color.rgb(random.nextInt() % 256, random.nextInt() % 256, random.nextInt() % 256); } }