Mercurial Hosting > nabble
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); + } + +}