blob: 26a6d47e3e1652b0c7479fdd82c3e59e65e15fda [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.syncbase;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import io.v.syncbase.core.Permissions;
/**
* Specifies access levels for a set of users. Each user has an associated access level: read-only,
* read-write, or read-write-admin.
*/
public class AccessList {
public enum AccessLevel {
READ,
READ_WRITE,
READ_WRITE_ADMIN
}
public Map<String, AccessLevel> users;
private static Set<String> parsedAccessListToUserIds(Map<String, Set<String>> accessList) {
Set<String> res = new HashSet<>();
if (accessList.containsKey(Permissions.NOT_IN) &&
!accessList.get(Permissions.NOT_IN).isEmpty()) {
throw new RuntimeException("Non-empty not-in section: " + accessList);
}
for (String blessingPattern : accessList.get(Permissions.IN)) {
// TODO(sadovsky): Ignore cloud peer's blessing pattern?
res.add(Syncbase.getEmailFromBlessingPattern(blessingPattern));
}
return res;
}
/**
* Creates an empty access list.
*/
public AccessList() {
this.users = new HashMap<>();
}
protected AccessList(Permissions corePermissions) {
Map<String, Map<String, Set<String>>> parsedPermissions = corePermissions.parse();
Set<String> resolvers = parsedAccessListToUserIds(parsedPermissions.get(Permissions.Tags.RESOLVE));
Set<String> readers = parsedAccessListToUserIds(parsedPermissions.get(Permissions.Tags.READ));
Set<String> writers = parsedAccessListToUserIds(parsedPermissions.get(Permissions.Tags.WRITE));
Set<String> admins = parsedAccessListToUserIds(parsedPermissions.get(Permissions.Tags.ADMIN));
if (!readers.containsAll(writers)) {
throw new RuntimeException("Some readers are not resolvers: " + readers + ", " + resolvers);
}
if (!readers.containsAll(writers)) {
throw new RuntimeException("Some writers are not readers: " + writers + ", " + readers);
}
if (!writers.containsAll(admins)) {
throw new RuntimeException("Some admins are not writers: " + admins + ", " + writers);
}
for (String userId : readers) {
users.put(userId, AccessLevel.READ);
}
for (String userId : writers) {
users.put(userId, AccessLevel.READ_WRITE);
}
for (String userId : admins) {
users.put(userId, AccessLevel.READ_WRITE_ADMIN);
}
}
private static void addToVAccessList(Map<String, Set<String>> accessList, String blessing) {
if (!accessList.get(Permissions.IN).contains(blessing)) {
accessList.get(Permissions.IN).add(blessing);
}
}
private static void removeFromVAccessList(Map<String, Set<String>> accessList, String blessing) {
accessList.get(Permissions.IN).remove(blessing);
}
/**
* Computes a new Permissions object based on delta.
*/
protected static Permissions applyDelta(Permissions corePermissions, AccessList delta) {
Map<String, Map<String, Set<String>>> parsedPermissions = corePermissions.parse();
for (String userId : delta.users.keySet()) {
AccessLevel level = delta.users.get(userId);
String blessing = Syncbase.getBlessingStringFromEmail(userId);
if (level == null) {
removeFromVAccessList(parsedPermissions.get(Permissions.Tags.RESOLVE), blessing);
removeFromVAccessList(parsedPermissions.get(Permissions.Tags.READ), blessing);
removeFromVAccessList(parsedPermissions.get(Permissions.Tags.WRITE), blessing);
removeFromVAccessList(parsedPermissions.get(Permissions.Tags.ADMIN), blessing);
continue;
}
switch (level) {
case READ:
addToVAccessList(parsedPermissions.get(Permissions.Tags.RESOLVE), blessing);
addToVAccessList(parsedPermissions.get(Permissions.Tags.READ), blessing);
removeFromVAccessList(parsedPermissions.get(Permissions.Tags.WRITE), blessing);
removeFromVAccessList(parsedPermissions.get(Permissions.Tags.ADMIN), blessing);
break;
case READ_WRITE:
addToVAccessList(parsedPermissions.get(Permissions.Tags.RESOLVE), blessing);
addToVAccessList(parsedPermissions.get(Permissions.Tags.READ), blessing);
addToVAccessList(parsedPermissions.get(Permissions.Tags.WRITE), blessing);
removeFromVAccessList(parsedPermissions.get(Permissions.Tags.ADMIN), blessing);
break;
case READ_WRITE_ADMIN:
addToVAccessList(parsedPermissions.get(Permissions.Tags.RESOLVE), blessing);
addToVAccessList(parsedPermissions.get(Permissions.Tags.READ), blessing);
addToVAccessList(parsedPermissions.get(Permissions.Tags.WRITE), blessing);
addToVAccessList(parsedPermissions.get(Permissions.Tags.ADMIN), blessing);
break;
}
}
return new Permissions(parsedPermissions);
}
}