diff src/nabble/view/lib/Permissions.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children 18cf4872fd7f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/nabble/view/lib/Permissions.java	Thu Mar 21 19:15:52 2019 -0600
@@ -0,0 +1,542 @@
+package nabble.view.lib;
+
+import fschmidt.db.Listener;
+import fschmidt.db.ListenerList;
+import fschmidt.util.java.Filter;
+import nabble.model.Db;
+import nabble.model.Init;
+import nabble.model.Node;
+import nabble.model.Person;
+import nabble.model.Site;
+import nabble.model.User;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+
+public final class Permissions {
+	private Permissions() {}  // never
+
+	private static String encode(String s) {
+		StringBuilder buf = new StringBuilder();
+		int n = s.length();
+		for( int i=0; i<n; i++ ) {
+			char c = s.charAt(i);
+			if( c == '\'' )
+				buf.append('\'');
+			buf.append(c);
+		}
+		return buf.toString();
+	}
+
+	private static void dbCheck(Site site) {
+		if( !site.getDb().isInTransaction() )
+			throw new RuntimeException("not in transaction");
+	}
+
+	public static boolean isInGroup(User user,String group) {
+		return user.getSite().hasTags(null,user,
+			"label='group:" + encode(group) + "'"
+		);
+	}
+
+	public static void addToGroup(User user,String group) {
+		Site site = user.getSite();
+		dbCheck(site);
+		site.addTag( null, user, "group:" + group );
+		groupChangeListeners.event(site);
+	}
+
+	public static void removeFromGroup(User user,String group) {
+		Site site = user.getSite();
+		dbCheck(site);
+		user.getSite().deleteTags(null,user,
+			"label='group:" + encode(group) + "'"
+		);
+		groupChangeListeners.event(site);
+	}
+
+	public static void removeGroup(Site site,String group) {
+		site.deleteTags(
+			"node_id is null and user_id is not null and label='group:" + encode(group) + "'"
+		);
+		groupChangeListeners.event(site);
+	}
+
+	public static void removeGroups(User user) {
+		user.getSite().deleteTags(null,user,
+			"label like 'group:%'"
+		);
+		groupChangeListeners.event(user.getSite());
+	}
+
+	private static List<String> getGroups(Site site,String sqlCondition) {
+		List<String> list = new ArrayList<String>();
+		for( String label : site.findTagLabels(sqlCondition) ) {
+			list.add( label.substring(6) );
+		}
+		return list;
+	}
+
+	public static List<String> getGroups(User user) {
+		return getGroups( user.getSite(),
+			"node_id is null and user_id=" + user.getId() + " and label like 'group:%'"
+		);
+	}
+
+	public static List<String> getGroups(Site site) {
+		return getGroups( site,
+			"node_id is null and user_id is not null and label like 'group:%'"
+		);
+	}
+
+	public static List<User> getUsersInGroup(Site site,String group) {
+		return site.findTagUsers(
+			"node_id is null and user_id is not null and label='group:" + encode(group) + "'"
+		);
+	}
+
+	public static void addPermission(Node node,String permission) {
+		Site site = node.getSite();
+		dbCheck(site);
+		site.addTag( node, null, "permission:" + permission );
+		permissionChangeListeners.event(site);
+	}
+
+	public static void addPermission(Node node,String permission,String group) {
+		Site site = node.getSite();
+		dbCheck(site);
+		if( !nodeHasPermission(node,permission) )
+			addPermission(node,permission);
+		site.addTag( node, null, "permission:" + permission + ":" + group );
+		permissionChangeListeners.event(site);
+	}
+
+	public static void addPermission(Site site,String permission,String group) {
+		dbCheck(site);
+		if( !siteHasPermission(site,permission) )
+			site.addTag( null, null, "permission:" + permission );
+		site.addTag( null, null, "permission:" + permission + ":" + group );
+		permissionChangeListeners.event(site);
+	}
+
+	public static void removePermission(Node node,String permission,String group) {
+		Site site = node.getSite();
+		dbCheck(site);
+		site.deleteTags(node,null,
+			"label='permission:" + encode(permission) + ":" + encode(group) + "'"
+		);
+		permissionChangeListeners.event(site);
+	}
+
+	public static void removePermission(Node node,String permission) {
+		Site site = node.getSite();
+		site.deleteTags(node,null,
+			"(label = 'permission:" + encode(permission) + "'"
+				+ " or label like 'permission:" + encode(permission) + ":%')"
+		);
+		permissionChangeListeners.event(site);
+	}
+
+	public static void removePermissions(Node node) {
+		Site site = node.getSite();
+		dbCheck(site);
+		site.deleteTags(node,null,
+			"label like 'permission:%'"
+		);
+		permissionChangeListeners.event(site);
+	}
+
+	public static boolean isPermissionVersion(Site site,String version) {
+		return site.hasTags(null,null,
+			"label='permission-version:" + version + "'"
+		);
+	}
+
+	public static void setPermissionVersion(Site site,String version) {
+		dbCheck(site);
+		deletePermissionVersion(site);
+		site.addTag( null, null, "permission-version:" + version );
+	}
+
+	public static void deletePermissionVersion(Site site) {
+		site.deleteTags(null,null,
+			"(label like 'permission:%' or label like 'site_default_permission:%' or label like 'permission-version:%')"
+		);
+	}
+
+	private static String query(Node node) {
+		return node==null ? "node_id is null" : "node_id=" + node.getId();
+	}
+
+	private static boolean siteHasPermission(Site site,String permission) {
+		return site.hasTags(null,null,
+			"label='permission:" + encode(permission) + "'"
+		);
+	}
+
+	public static boolean nodeHasPermission(Node node,String permission) {
+		return node.getSite().hasTags(node,null,
+			"label='permission:" + encode(permission) + "'"
+		);
+	}
+
+	public static Node getPermissionNode(Node node,String permission) {
+		for( Node n : node.getAncestors() ) {
+			if( nodeHasPermission(n,permission) )
+				return n;
+		}
+		return null;
+	}
+
+	public static List<String> getGroupsWithPermission(Node node,String permission) {
+		Site site = node.getSite();
+		node = getPermissionNode(node,permission);
+		if( node == null && !siteHasPermission(site,permission) )
+			return Collections.emptyList();
+		List<String> list = new ArrayList<String>();
+		String labelStart = "permission:" + encode(permission) + ":";
+		int i = labelStart.length();
+		for( String label : site.findTagLabels(
+			query(node) + " and user_id is null and label like '" + labelStart + "%'"
+		) ) {
+			list.add( label.substring(i) );
+		}
+		return list;
+	}
+
+	public static boolean hasGroupsWithPermission(Node node,String permission) {
+		Site site = node.getSite();
+		node = getPermissionNode(node,permission);
+		if( node == null && !siteHasPermission(site,permission) )
+			return false;
+		return site.hasTags(node,null,
+			"label like 'permission:" + encode(permission) + ":%'"
+		);
+	}
+
+	public static final String ANYONE_GROUP = "Anyone";
+	public static final String REGISTERED_GROUP = "Registered";
+	public static final String AUTHOR_GROUP = "Authors";
+	public static final String ADMINISTRATORS_GROUP = "Administrators";
+
+	public static List<String> getPersonGroups(Person person) {
+		List<String> groups;
+		if (person instanceof User) {
+			User user = (User) person;
+			groups = getGroups((User) person);
+			if (user.isRegistered())
+				groups.add(REGISTERED_GROUP);
+		} else {
+			groups = new ArrayList<String>();
+		}
+		groups.add(ANYONE_GROUP);
+		return groups;
+	}
+
+	public static boolean hasPermission(Node permissionNode,Node targetNode,Person person,String permission) {
+		Person owner = targetNode.getOwner();
+		Site site = permissionNode.getSite();
+		permissionNode = getPermissionNode(permissionNode,permission);
+		if( permissionNode == null && !siteHasPermission(site,permission) )
+			return false;
+		String s = "label='permission:" + encode(permission) + ":";
+		List<String> groups = getPersonGroups(person);
+		if( owner.equals(person) )
+			groups.add(AUTHOR_GROUP);
+		for( String group : groups ) {
+			if( site.hasTags(permissionNode,null, s + encode(group) + "'" ) )
+				return true;
+		}
+		return false;
+	}
+
+	public static boolean hasPermission(Node node,String group,String permission) {
+		Site site = node.getSite();
+		node = getPermissionNode(node,permission);
+		if( node == null && !siteHasPermission(site,permission) )
+			return false;
+		return hasPermission(site,node,group,permission);
+	}
+
+	private static boolean hasPermission(Site site,Node node,String group,String permission) {
+		return site.hasTags(node,null,
+			"label='permission:" + encode(permission) + ":" + encode(group) + "'"
+		);
+	}
+
+	public static boolean hasPermission(Site site,String group,String permission) {
+		return siteHasPermission(site,permission) && site.hasTags(null,null,
+			"label='permission:" + encode(permission) + ":" + encode(group) + "'"
+		);
+	}
+
+	public static List<User> getUsersWithPermission(Node node,String permission) {
+		Site site = node.getSite();
+		node = getPermissionNode(node,permission);
+		if( node == null && !siteHasPermission(site,permission) )
+			return Collections.emptyList();
+		if (hasPermission(site, node, ANYONE_GROUP,permission))
+			return site.getUsers(null);
+		else if (hasPermission(site, node, REGISTERED_GROUP,permission))
+			return site.getUsers("registered is not null");
+		String labelStart = "permission:" + encode(permission) + ":";
+		int i = labelStart.length();
+		return site.findTagUsers(
+			"node_id is null and user_id is not null and label in ("
+			+	"select 'group:' || substring(label," + (i+1) + ") from tag where " + query(node) + " and user_id is null and label like '" + labelStart + "%'"
+			+")"
+		);
+	}
+
+
+	public static final String VIEW_PERMISSION = "View";
+
+	public static boolean isPrivate(Node node) {
+		return getPrivateNode(node) != null;
+	}
+
+	public static boolean canBeViewedByParentViewers(Node node) {
+		if( node.getKind() != Node.Kind.APP )
+			return true;
+		if( !nodeHasPermission(node,VIEW_PERMISSION) )
+			return true;
+		Node parent = node.getParent();
+		if( parent != null )
+			parent = getPrivateNode(parent);
+		if( parent == null && !siteHasPermission(node.getSite(),VIEW_PERMISSION) )
+			return !isPrivate(node);
+		return !node.getSite().hasTags(parent,null,
+			"label like 'permission:View:%'"
+			+" and label not in (select label from tag where node_id=" + node.getId() + " and user_id is null and label like 'permission:View:%')"
+		);
+	}
+
+	public static final Filter<Node> canBeViewedByParentViewersFilter = new Filter<Node>() {
+		public boolean ok(Node node) {
+			return canBeViewedByParentViewers(node);
+		}
+	};
+
+	public static boolean canBeViewedByPerson(Node node,Person person) {
+		if( person instanceof User ) {
+			User user = (User)person;
+			if( isSysAdmin(user) )
+				return true;
+			if( isInGroup(user,ADMINISTRATORS_GROUP) )
+				return true;
+		}
+		if( node.getSite().getRootNode().getOwner().equals(person) )
+			return true;
+		Node permissionNode = node.getApp();
+		if( permissionNode==null )
+			permissionNode = node.getSite().getRootNode();
+		return hasPermission(permissionNode,node,person,VIEW_PERMISSION);
+	}
+
+	public static final Filter<Node> canBeViewedByPersonFilter(final Person person) {
+		return new Filter<Node>() {
+			public boolean ok(Node node) {
+				return canBeViewedByPerson(node,person);
+			}
+		};
+	}
+
+	public static Node getPrivateNode(Node node) {
+		node = getPermissionNode(node,VIEW_PERMISSION);
+		return node==null || hasPermission(node.getSite(),node,ANYONE_GROUP,VIEW_PERMISSION) ? null : node;
+	}
+
+	public static Node getPrivateNodeForSearch(Node node) {
+		node = getPrivateNode(node);
+		while( node != null && canBeViewedByParentViewers(node) ) {
+			node = getPrivateNode(node.getParent());
+		}
+		return node;
+	}
+
+	// Banning ------------------------------------------------------
+
+	public static boolean isBanned(User user) {
+		return user.getSite().hasTags(null,user,"label='banned'");
+	}
+
+	public static void ban(User user) {
+		user.getSite().addTag(null, user, "banned");
+	}
+
+	public static void unban(User user) {
+		user.getSite().deleteTags(null,user,"label='banned'");
+	}
+
+	public static List<User> getBannedUsers(Site site) {
+		return site.findTagUsers(
+			"node_id is null and user_id is not null and label='banned'"
+		);
+	}
+
+
+
+	private static final Set<String> sysadmins = Init.get("sysadmins",Collections.<String>emptySet());
+
+	public static boolean isSysAdmin(User user) {
+		return sysadmins.contains(user.getEmail());
+	}
+
+
+	// site permissions
+
+	public static void addSitePermission(Site site,String permission) {
+		dbCheck(site);
+		site.addTag( null, null, "site_permission:" + permission );
+	}
+
+	public static void addSiteDefaultPermission(Site site,String permission) {
+		dbCheck(site);
+		site.addTag( null, null, "site_default_permission:" + permission );
+	}
+
+	private static boolean hasSitePermission(Site site,String permission) {
+		return site.hasTags(null,null,
+			"label='site_permission:" + encode(permission) + "'"
+		);
+	}
+
+	public static boolean siteHasSitePermission(Site site,String permission) {
+		return hasSitePermission(site,permission);
+	}
+
+	private static boolean hasSiteDefaultPermission(Site site,String permission) {
+		return site.hasTags(null,null,
+			"label='site_default_permission:" + encode(permission) + "'"
+		);
+	}
+
+	public static void addSitePermission(Site site,String permission,String group) {
+		dbCheck(site);
+		if( !hasSitePermission(site,permission) )
+			site.addTag( null, null, "site_permission:" + permission );
+		site.addTag( null, null, "site_permission:" + permission + ":" + group );
+	}
+
+	public static void addSiteDefaultPermission(Site site,String permission,String group) {
+		dbCheck(site);
+		if( !hasSiteDefaultPermission(site,permission) )
+			site.addTag( null, null, "site_default_permission:" + permission );
+		site.addTag( null, null, "site_default_permission:" + permission + ":" + group );
+	}
+
+	public static void removeSitePermission(Site site,String permission,String group) {
+		dbCheck(site);
+		site.deleteTags(null,null,
+			"label='site_permission:" + encode(permission) + ":" + encode(group) + "'"
+		);
+	}
+
+	public static void removeSitePermission(Site site,String permission) {
+		site.deleteTags(null,null,
+			"(label = 'site_permission:" + encode(permission) + "'"
+				+ " or label like 'site_permission:" + encode(permission) + ":%')"
+		);
+	}
+
+	public static void removeSitePermissions(Site site) {
+		dbCheck(site);
+		site.deleteTags(null,null,
+			"label like 'site_permission:%'"
+		);
+	}
+
+	private static String sitePermissionLabel(Site site,String permission) {
+		if( hasSitePermission(site,permission) )
+			return "site_permission:" + encode(permission);
+		else if( hasSiteDefaultPermission(site,permission) )
+			return "site_default_permission:" + encode(permission);
+		else
+			return null;
+	}
+
+	public static List<String> getGroupsWithSitePermission(Site site,String permission) {
+		String labelStart = sitePermissionLabel(site,permission);
+		if( labelStart == null )
+			return Collections.emptyList();
+		List<String> list = new ArrayList<String>();
+		int i = labelStart.length();
+		for( String label : site.findTagLabels(
+			"node_id is null and user_id is null and label like '" + labelStart + ":%'"
+		) ) {
+			list.add( label.substring(i) );
+		}
+		return list;
+	}
+
+	public static boolean hasGroupsWithSitePermission(Site site,String permission) {
+		String labelStart = sitePermissionLabel(site,permission);
+		if( labelStart == null )
+			return false;
+		return site.hasTags(null,null,
+			"label like '" + labelStart + ":%'"
+		);
+	}
+
+	public static boolean hasSitePermission(Site site,Person person,String permission) {
+		String labelStart = sitePermissionLabel(site,permission);
+		if( labelStart == null )
+			return false;
+		String s = "label='" + labelStart + ":";
+		List<String> groups = getPersonGroups(person);
+		for( String group : groups ) {
+			if( site.hasTags(null,null, s + encode(group) + "'" ) )
+				return true;
+		}
+		return false;
+	}
+
+	public static boolean hasSitePermission(Site site,String group,String permission) {
+		String labelStart = sitePermissionLabel(site,permission);
+		if( labelStart == null )
+			return false;
+		return site.hasTags(null,null,
+			"label='" + labelStart + ":" + encode(group) + "'"
+		);
+	}
+
+	public static boolean hasSiteDefaultPermission(Site site,String group,String permission) {
+		return hasSiteDefaultPermission(site,permission) && site.hasTags(null,null,
+			"label='site_default_permission:" + encode(permission) + ":" + encode(group) + "'"
+		);
+	}
+
+	public static List<User> getUsersWithSitePermission(Site site,String permission) {
+		String labelStart = sitePermissionLabel(site,permission);
+		if (labelStart == null)
+			return Collections.emptyList();
+		if (hasSitePermission(site,ANYONE_GROUP,permission))
+			return site.getUsers(null);
+		else if (hasSitePermission(site,REGISTERED_GROUP,permission))
+			return site.getUsers("registered is not null");
+		labelStart += ":";
+		int i = labelStart.length();
+		return site.findTagUsers(
+			"node_id is null and user_id is not null and label in ("
+			+	"select 'group:' || substring(label," + (i+1) + ") from tag where node is null and user_id is null and label like '" + labelStart + "%'"
+			+")"
+		);
+	}
+
+
+	private static final ListenerList<Site> groupChangeListeners = new ListenerList<Site>();
+
+	public static void addGroupChangeListener(final Listener<Site> listener) {
+		groupChangeListeners.add(listener);
+	}
+
+	private static final ListenerList<Site> permissionChangeListeners = new ListenerList<Site>();
+
+	public static void addPermissionChangeListener(final Listener<Site> listener) {
+		permissionChangeListeners.add(listener);
+	}
+
+}