package org.lntu.online.model.storage; import android.content.Context; import android.content.SharedPreferences; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Base64; import android.util.Log; import com.google.gson.JsonParseException; import org.lntu.online.model.util.EntityUtils; import org.lntu.online.util.Crypto; import org.lntu.online.util.Digest; import java.lang.reflect.Type; import java.nio.charset.Charset; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; public final class SharedWrapper { private static final String TAG = "SharedWrapper"; private static final Charset CHARSET_UTF_8 = Charset.forName("UTF-8"); private static SecretKey secretSingleton = null; private static IvParameterSpec ivSingleton = null; public static SharedWrapper with(@NonNull Context context, @NonNull String name) { if (secretSingleton == null || ivSingleton == null) { synchronized (SharedWrapper.class) { if (secretSingleton == null) { secretSingleton = Crypto.AES.generateSecret(Digest.SHA256.getRaw(DeviceInfo.getDeviceToken(context))); } if (ivSingleton == null) { ivSingleton = Crypto.AES.generateIV(Digest.MD5.getRaw(DeviceInfo.getDeviceToken(context))); } } } return new SharedWrapper(context, name, secretSingleton, ivSingleton); } private final SharedPreferences sp; private final SecretKey secret; private final IvParameterSpec iv; private SharedWrapper(@NonNull Context context, @NonNull String name, @NonNull SecretKey secret, @NonNull IvParameterSpec iv) { sp = context.getSharedPreferences(Digest.MD5.getHex(name), Context.MODE_PRIVATE); this.secret = secret; this.iv = iv; } private String get(@NonNull String key, @Nullable String defValue) { String target = sp.getString(Digest.MD5.getHex(key), null); if (target == null) { return defValue; } else { try { return new String(Crypto.AES.decrypt(secret, iv, Base64.decode(target, Base64.DEFAULT)), CHARSET_UTF_8); } catch (Crypto.CryptoException e) { Log.e(TAG, "value decrypt error at key :" + key, e); return defValue; } } } private void set(@NonNull String key, @Nullable String value) { String target; if (value == null) { target = null; } else { try { target = Base64.encodeToString(Crypto.AES.encrypt(secret, iv, value.getBytes(CHARSET_UTF_8)), Base64.DEFAULT); } catch (Crypto.CryptoException e) { Log.e(TAG, "value encrypt error at key :" + key, e); target = null; } } sp.edit().putString(Digest.MD5.getHex(key), target).apply(); } public void clear() { sp.edit().clear().apply(); } public String getString(@NonNull String key, @Nullable String defValue) { return get(key, defValue); } public void setString(@NonNull String key, @Nullable String value) { set(key, value); } public boolean getBoolean(@NonNull String key, boolean defValue) { String value = get(key, null); if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) { return Boolean.parseBoolean(value); } else { if (value != null) { Log.e(TAG, "parse boolean error -> " + key + " : " + value); } return defValue; } } public void setBoolean(@NonNull String key, boolean value) { set(key, Boolean.toString(value)); } public float getFloat(@NonNull String key, float defValue) { String value = get(key, null); if (value == null) { return defValue; } else { try { return Float.parseFloat(value); } catch (NumberFormatException e) { Log.e(TAG, "parse float error -> " + key + " : " + value); return defValue; } } } public void setFloat(@NonNull String key, float value) { set(key, Float.toString(value)); } public int getInt(@NonNull String key, int defValue) { String value = get(key, null); if (value == null) { return defValue; } else { try { return Integer.parseInt(value); } catch (NumberFormatException e) { Log.e(TAG, "parse int error -> " + key + " : " + value); return defValue; } } } public void setInt(@NonNull String key, int value) { set(key, Integer.toString(value)); } public long getLong(@NonNull String key, long defValue) { String value = get(key, null); if (value == null) { return defValue; } else { try { return Long.parseLong(value); } catch (NumberFormatException e) { Log.e(TAG, "parse long error -> " + key + " : " + value); return defValue; } } } public void setLong(@NonNull String key, long value) { set(key, Long.toString(value)); } public <T> T getObject(@NonNull String key, @NonNull Type typeOfT) { String value = get(key, null); if (value == null) { return null; } else { try { return EntityUtils.gson.fromJson(value, typeOfT); } catch (JsonParseException e) { Log.e(TAG, "parse object error -> " + key + " : " + value); return null; } } } public void setObject(@NonNull String key, @Nullable Object value) { set(key, value == null ? null : EntityUtils.gson.toJson(value)); } }