package org.lobobrowser.security;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Optional;
import org.javatuples.Pair;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Result;
import org.lobobrowser.security.PermissionSystem.Permission;
import org.lobobrowser.store.StorageManager;
import org.lobobrowser.ua.UserAgentContext.RequestKind;
import info.gngr.db.tables.Globals;
import info.gngr.db.tables.Permissions;
import info.gngr.db.tables.records.PermissionsRecord;
public class DBRequestRuleStore implements RequestRuleStore {
private final DSLContext userDB;
private static final Permission[] defaultPermissions = new Permission[RequestKind.numKinds()];
static {
for (int i = 0; i < defaultPermissions.length; i++) {
defaultPermissions[i] = Permission.Undecided;
}
}
private static final Pair<Permission, Permission[]> defaultPermissionPair = Pair.with(Permission.Undecided, defaultPermissions);
static private DBRequestRuleStore instance = new DBRequestRuleStore();
public static DBRequestRuleStore getInstance() {
return instance;
}
public DBRequestRuleStore() {
final StorageManager storageManager = StorageManager.getInstance();
userDB = storageManager.getDB();
if (!userDB.fetchOne(Globals.GLOBALS).getPermissionsinitialized()) {
HelperPrivate.initStore(this);
userDB.fetchOne(Globals.GLOBALS).setPermissionsinitialized(true);
}
}
private static Condition matchHostsCondition(final String frameHost, final String requestHost) {
return Permissions.PERMISSIONS.FRAMEHOST.equal(frameHost).and(Permissions.PERMISSIONS.REQUESTHOST.equal(requestHost));
}
public Pair<Permission, Permission[]> getPermissions(final String frameHostPattern, final String requestHost) {
final Result<PermissionsRecord> permissionRecords = AccessController.doPrivileged((PrivilegedAction<Result<PermissionsRecord>>) () -> {
return userDB.fetch(Permissions.PERMISSIONS, matchHostsCondition(frameHostPattern, requestHost));
});
if (permissionRecords.isEmpty()) {
return defaultPermissionPair;
} else {
final PermissionsRecord existingRecord = permissionRecords.get(0);
final Integer existingPermissions = existingRecord.getPermissions();
final Pair<Permission, Permission[]> permissions = decodeBitMask(existingPermissions);
return permissions;
}
}
private static Pair<Permission, Permission[]> decodeBitMask(final Integer existingPermissions) {
final Permission[] resultPermissions = new Permission[RequestKind.numKinds()];
for (int i = 0; i < resultPermissions.length; i++) {
resultPermissions[i] = decodeBits(existingPermissions, i + 1);
}
final Pair<Permission, Permission[]> resultPair = Pair.with(decodeBits(existingPermissions, 0), resultPermissions);
return resultPair;
}
private static final int BITS_PER_KIND = 2;
private static Permission decodeBits(final Integer existingPermissions, final int i) {
final int permissionBits = (existingPermissions >> (i * BITS_PER_KIND)) & 0x3;
if (permissionBits < 2) {
return Permission.Undecided;
} else {
return permissionBits == 0x3 ? Permission.Allow : Permission.Deny;
}
}
public void storePermissions(final String frameHost, final String requestHost, final Optional<RequestKind> kindOpt,
final Permission permission) {
final Result<PermissionsRecord> permissionRecords = AccessController.doPrivileged((PrivilegedAction<Result<PermissionsRecord>>) () -> {
return userDB.fetch(Permissions.PERMISSIONS, matchHostsCondition(frameHost, requestHost));
});
final Integer permissionMask = makeBitSetMask(kindOpt, permission);
if (permissionRecords.isEmpty()) {
final PermissionsRecord newPermissionRecord = new PermissionsRecord(frameHost, requestHost, permissionMask);
newPermissionRecord.attach(userDB.configuration());
newPermissionRecord.store();
} else {
final PermissionsRecord existingRecord = permissionRecords.get(0);
final Integer existingPermissions = existingRecord.getPermissions();
final int newPermissions = (existingPermissions & makeBitBlockMask(kindOpt)) | permissionMask;
existingRecord.setPermissions(newPermissions);
existingRecord.store();
}
}
private static Integer makeBitSetMask(final Optional<RequestKind> kindOpt, final Permission permission) {
if (permission.isDecided()) {
final Integer bitPos = kindOpt.map(k -> k.ordinal() + 1).orElse(0) * BITS_PER_KIND;
final int bitset = permission == Permission.Allow ? 0x3 : 0x2;
return bitset << bitPos;
} else {
return 0;
}
}
private static Integer makeBitBlockMask(final Optional<RequestKind> kindOpt) {
final Integer bitPos = kindOpt.map(k -> k.ordinal() + 1).orElse(0) * BITS_PER_KIND;
return ~(0x3 << bitPos);
}
}