Mercurial Hosting > nabble
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:7ecd1a4ef557 |
---|---|
1 package nabble.view.lib; | |
2 | |
3 import fschmidt.db.Listener; | |
4 import fschmidt.db.ListenerList; | |
5 import fschmidt.util.java.Filter; | |
6 import nabble.model.Db; | |
7 import nabble.model.Init; | |
8 import nabble.model.Node; | |
9 import nabble.model.Person; | |
10 import nabble.model.Site; | |
11 import nabble.model.User; | |
12 | |
13 import java.util.ArrayList; | |
14 import java.util.Collections; | |
15 import java.util.List; | |
16 import java.util.Set; | |
17 | |
18 | |
19 public final class Permissions { | |
20 private Permissions() {} // never | |
21 | |
22 private static String encode(String s) { | |
23 StringBuilder buf = new StringBuilder(); | |
24 int n = s.length(); | |
25 for( int i=0; i<n; i++ ) { | |
26 char c = s.charAt(i); | |
27 if( c == '\'' ) | |
28 buf.append('\''); | |
29 buf.append(c); | |
30 } | |
31 return buf.toString(); | |
32 } | |
33 | |
34 private static void dbCheck(Site site) { | |
35 if( !site.getDb().isInTransaction() ) | |
36 throw new RuntimeException("not in transaction"); | |
37 } | |
38 | |
39 public static boolean isInGroup(User user,String group) { | |
40 return user.getSite().hasTags(null,user, | |
41 "label='group:" + encode(group) + "'" | |
42 ); | |
43 } | |
44 | |
45 public static void addToGroup(User user,String group) { | |
46 Site site = user.getSite(); | |
47 dbCheck(site); | |
48 site.addTag( null, user, "group:" + group ); | |
49 groupChangeListeners.event(site); | |
50 } | |
51 | |
52 public static void removeFromGroup(User user,String group) { | |
53 Site site = user.getSite(); | |
54 dbCheck(site); | |
55 user.getSite().deleteTags(null,user, | |
56 "label='group:" + encode(group) + "'" | |
57 ); | |
58 groupChangeListeners.event(site); | |
59 } | |
60 | |
61 public static void removeGroup(Site site,String group) { | |
62 site.deleteTags( | |
63 "node_id is null and user_id is not null and label='group:" + encode(group) + "'" | |
64 ); | |
65 groupChangeListeners.event(site); | |
66 } | |
67 | |
68 public static void removeGroups(User user) { | |
69 user.getSite().deleteTags(null,user, | |
70 "label like 'group:%'" | |
71 ); | |
72 groupChangeListeners.event(user.getSite()); | |
73 } | |
74 | |
75 private static List<String> getGroups(Site site,String sqlCondition) { | |
76 List<String> list = new ArrayList<String>(); | |
77 for( String label : site.findTagLabels(sqlCondition) ) { | |
78 list.add( label.substring(6) ); | |
79 } | |
80 return list; | |
81 } | |
82 | |
83 public static List<String> getGroups(User user) { | |
84 return getGroups( user.getSite(), | |
85 "node_id is null and user_id=" + user.getId() + " and label like 'group:%'" | |
86 ); | |
87 } | |
88 | |
89 public static List<String> getGroups(Site site) { | |
90 return getGroups( site, | |
91 "node_id is null and user_id is not null and label like 'group:%'" | |
92 ); | |
93 } | |
94 | |
95 public static List<User> getUsersInGroup(Site site,String group) { | |
96 return site.findTagUsers( | |
97 "node_id is null and user_id is not null and label='group:" + encode(group) + "'" | |
98 ); | |
99 } | |
100 | |
101 public static void addPermission(Node node,String permission) { | |
102 Site site = node.getSite(); | |
103 dbCheck(site); | |
104 site.addTag( node, null, "permission:" + permission ); | |
105 permissionChangeListeners.event(site); | |
106 } | |
107 | |
108 public static void addPermission(Node node,String permission,String group) { | |
109 Site site = node.getSite(); | |
110 dbCheck(site); | |
111 if( !nodeHasPermission(node,permission) ) | |
112 addPermission(node,permission); | |
113 site.addTag( node, null, "permission:" + permission + ":" + group ); | |
114 permissionChangeListeners.event(site); | |
115 } | |
116 | |
117 public static void addPermission(Site site,String permission,String group) { | |
118 dbCheck(site); | |
119 if( !siteHasPermission(site,permission) ) | |
120 site.addTag( null, null, "permission:" + permission ); | |
121 site.addTag( null, null, "permission:" + permission + ":" + group ); | |
122 permissionChangeListeners.event(site); | |
123 } | |
124 | |
125 public static void removePermission(Node node,String permission,String group) { | |
126 Site site = node.getSite(); | |
127 dbCheck(site); | |
128 site.deleteTags(node,null, | |
129 "label='permission:" + encode(permission) + ":" + encode(group) + "'" | |
130 ); | |
131 permissionChangeListeners.event(site); | |
132 } | |
133 | |
134 public static void removePermission(Node node,String permission) { | |
135 Site site = node.getSite(); | |
136 site.deleteTags(node,null, | |
137 "(label = 'permission:" + encode(permission) + "'" | |
138 + " or label like 'permission:" + encode(permission) + ":%')" | |
139 ); | |
140 permissionChangeListeners.event(site); | |
141 } | |
142 | |
143 public static void removePermissions(Node node) { | |
144 Site site = node.getSite(); | |
145 dbCheck(site); | |
146 site.deleteTags(node,null, | |
147 "label like 'permission:%'" | |
148 ); | |
149 permissionChangeListeners.event(site); | |
150 } | |
151 | |
152 public static boolean isPermissionVersion(Site site,String version) { | |
153 return site.hasTags(null,null, | |
154 "label='permission-version:" + version + "'" | |
155 ); | |
156 } | |
157 | |
158 public static void setPermissionVersion(Site site,String version) { | |
159 dbCheck(site); | |
160 deletePermissionVersion(site); | |
161 site.addTag( null, null, "permission-version:" + version ); | |
162 } | |
163 | |
164 public static void deletePermissionVersion(Site site) { | |
165 site.deleteTags(null,null, | |
166 "(label like 'permission:%' or label like 'site_default_permission:%' or label like 'permission-version:%')" | |
167 ); | |
168 } | |
169 | |
170 private static String query(Node node) { | |
171 return node==null ? "node_id is null" : "node_id=" + node.getId(); | |
172 } | |
173 | |
174 private static boolean siteHasPermission(Site site,String permission) { | |
175 return site.hasTags(null,null, | |
176 "label='permission:" + encode(permission) + "'" | |
177 ); | |
178 } | |
179 | |
180 public static boolean nodeHasPermission(Node node,String permission) { | |
181 return node.getSite().hasTags(node,null, | |
182 "label='permission:" + encode(permission) + "'" | |
183 ); | |
184 } | |
185 | |
186 public static Node getPermissionNode(Node node,String permission) { | |
187 for( Node n : node.getAncestors() ) { | |
188 if( nodeHasPermission(n,permission) ) | |
189 return n; | |
190 } | |
191 return null; | |
192 } | |
193 | |
194 public static List<String> getGroupsWithPermission(Node node,String permission) { | |
195 Site site = node.getSite(); | |
196 node = getPermissionNode(node,permission); | |
197 if( node == null && !siteHasPermission(site,permission) ) | |
198 return Collections.emptyList(); | |
199 List<String> list = new ArrayList<String>(); | |
200 String labelStart = "permission:" + encode(permission) + ":"; | |
201 int i = labelStart.length(); | |
202 for( String label : site.findTagLabels( | |
203 query(node) + " and user_id is null and label like '" + labelStart + "%'" | |
204 ) ) { | |
205 list.add( label.substring(i) ); | |
206 } | |
207 return list; | |
208 } | |
209 | |
210 public static boolean hasGroupsWithPermission(Node node,String permission) { | |
211 Site site = node.getSite(); | |
212 node = getPermissionNode(node,permission); | |
213 if( node == null && !siteHasPermission(site,permission) ) | |
214 return false; | |
215 return site.hasTags(node,null, | |
216 "label like 'permission:" + encode(permission) + ":%'" | |
217 ); | |
218 } | |
219 | |
220 public static final String ANYONE_GROUP = "Anyone"; | |
221 public static final String REGISTERED_GROUP = "Registered"; | |
222 public static final String AUTHOR_GROUP = "Authors"; | |
223 public static final String ADMINISTRATORS_GROUP = "Administrators"; | |
224 | |
225 public static List<String> getPersonGroups(Person person) { | |
226 List<String> groups; | |
227 if (person instanceof User) { | |
228 User user = (User) person; | |
229 groups = getGroups((User) person); | |
230 if (user.isRegistered()) | |
231 groups.add(REGISTERED_GROUP); | |
232 } else { | |
233 groups = new ArrayList<String>(); | |
234 } | |
235 groups.add(ANYONE_GROUP); | |
236 return groups; | |
237 } | |
238 | |
239 public static boolean hasPermission(Node permissionNode,Node targetNode,Person person,String permission) { | |
240 Person owner = targetNode.getOwner(); | |
241 Site site = permissionNode.getSite(); | |
242 permissionNode = getPermissionNode(permissionNode,permission); | |
243 if( permissionNode == null && !siteHasPermission(site,permission) ) | |
244 return false; | |
245 String s = "label='permission:" + encode(permission) + ":"; | |
246 List<String> groups = getPersonGroups(person); | |
247 if( owner.equals(person) ) | |
248 groups.add(AUTHOR_GROUP); | |
249 for( String group : groups ) { | |
250 if( site.hasTags(permissionNode,null, s + encode(group) + "'" ) ) | |
251 return true; | |
252 } | |
253 return false; | |
254 } | |
255 | |
256 public static boolean hasPermission(Node node,String group,String permission) { | |
257 Site site = node.getSite(); | |
258 node = getPermissionNode(node,permission); | |
259 if( node == null && !siteHasPermission(site,permission) ) | |
260 return false; | |
261 return hasPermission(site,node,group,permission); | |
262 } | |
263 | |
264 private static boolean hasPermission(Site site,Node node,String group,String permission) { | |
265 return site.hasTags(node,null, | |
266 "label='permission:" + encode(permission) + ":" + encode(group) + "'" | |
267 ); | |
268 } | |
269 | |
270 public static boolean hasPermission(Site site,String group,String permission) { | |
271 return siteHasPermission(site,permission) && site.hasTags(null,null, | |
272 "label='permission:" + encode(permission) + ":" + encode(group) + "'" | |
273 ); | |
274 } | |
275 | |
276 public static List<User> getUsersWithPermission(Node node,String permission) { | |
277 Site site = node.getSite(); | |
278 node = getPermissionNode(node,permission); | |
279 if( node == null && !siteHasPermission(site,permission) ) | |
280 return Collections.emptyList(); | |
281 if (hasPermission(site, node, ANYONE_GROUP,permission)) | |
282 return site.getUsers(null); | |
283 else if (hasPermission(site, node, REGISTERED_GROUP,permission)) | |
284 return site.getUsers("registered is not null"); | |
285 String labelStart = "permission:" + encode(permission) + ":"; | |
286 int i = labelStart.length(); | |
287 return site.findTagUsers( | |
288 "node_id is null and user_id is not null and label in (" | |
289 + "select 'group:' || substring(label," + (i+1) + ") from tag where " + query(node) + " and user_id is null and label like '" + labelStart + "%'" | |
290 +")" | |
291 ); | |
292 } | |
293 | |
294 | |
295 public static final String VIEW_PERMISSION = "View"; | |
296 | |
297 public static boolean isPrivate(Node node) { | |
298 return getPrivateNode(node) != null; | |
299 } | |
300 | |
301 public static boolean canBeViewedByParentViewers(Node node) { | |
302 if( node.getKind() != Node.Kind.APP ) | |
303 return true; | |
304 if( !nodeHasPermission(node,VIEW_PERMISSION) ) | |
305 return true; | |
306 Node parent = node.getParent(); | |
307 if( parent != null ) | |
308 parent = getPrivateNode(parent); | |
309 if( parent == null && !siteHasPermission(node.getSite(),VIEW_PERMISSION) ) | |
310 return !isPrivate(node); | |
311 return !node.getSite().hasTags(parent,null, | |
312 "label like 'permission:View:%'" | |
313 +" and label not in (select label from tag where node_id=" + node.getId() + " and user_id is null and label like 'permission:View:%')" | |
314 ); | |
315 } | |
316 | |
317 public static final Filter<Node> canBeViewedByParentViewersFilter = new Filter<Node>() { | |
318 public boolean ok(Node node) { | |
319 return canBeViewedByParentViewers(node); | |
320 } | |
321 }; | |
322 | |
323 public static boolean canBeViewedByPerson(Node node,Person person) { | |
324 if( person instanceof User ) { | |
325 User user = (User)person; | |
326 if( isSysAdmin(user) ) | |
327 return true; | |
328 if( isInGroup(user,ADMINISTRATORS_GROUP) ) | |
329 return true; | |
330 } | |
331 if( node.getSite().getRootNode().getOwner().equals(person) ) | |
332 return true; | |
333 Node permissionNode = node.getApp(); | |
334 if( permissionNode==null ) | |
335 permissionNode = node.getSite().getRootNode(); | |
336 return hasPermission(permissionNode,node,person,VIEW_PERMISSION); | |
337 } | |
338 | |
339 public static final Filter<Node> canBeViewedByPersonFilter(final Person person) { | |
340 return new Filter<Node>() { | |
341 public boolean ok(Node node) { | |
342 return canBeViewedByPerson(node,person); | |
343 } | |
344 }; | |
345 } | |
346 | |
347 public static Node getPrivateNode(Node node) { | |
348 node = getPermissionNode(node,VIEW_PERMISSION); | |
349 return node==null || hasPermission(node.getSite(),node,ANYONE_GROUP,VIEW_PERMISSION) ? null : node; | |
350 } | |
351 | |
352 public static Node getPrivateNodeForSearch(Node node) { | |
353 node = getPrivateNode(node); | |
354 while( node != null && canBeViewedByParentViewers(node) ) { | |
355 node = getPrivateNode(node.getParent()); | |
356 } | |
357 return node; | |
358 } | |
359 | |
360 // Banning ------------------------------------------------------ | |
361 | |
362 public static boolean isBanned(User user) { | |
363 return user.getSite().hasTags(null,user,"label='banned'"); | |
364 } | |
365 | |
366 public static void ban(User user) { | |
367 user.getSite().addTag(null, user, "banned"); | |
368 } | |
369 | |
370 public static void unban(User user) { | |
371 user.getSite().deleteTags(null,user,"label='banned'"); | |
372 } | |
373 | |
374 public static List<User> getBannedUsers(Site site) { | |
375 return site.findTagUsers( | |
376 "node_id is null and user_id is not null and label='banned'" | |
377 ); | |
378 } | |
379 | |
380 | |
381 | |
382 private static final Set<String> sysadmins = Init.get("sysadmins",Collections.<String>emptySet()); | |
383 | |
384 public static boolean isSysAdmin(User user) { | |
385 return sysadmins.contains(user.getEmail()); | |
386 } | |
387 | |
388 | |
389 // site permissions | |
390 | |
391 public static void addSitePermission(Site site,String permission) { | |
392 dbCheck(site); | |
393 site.addTag( null, null, "site_permission:" + permission ); | |
394 } | |
395 | |
396 public static void addSiteDefaultPermission(Site site,String permission) { | |
397 dbCheck(site); | |
398 site.addTag( null, null, "site_default_permission:" + permission ); | |
399 } | |
400 | |
401 private static boolean hasSitePermission(Site site,String permission) { | |
402 return site.hasTags(null,null, | |
403 "label='site_permission:" + encode(permission) + "'" | |
404 ); | |
405 } | |
406 | |
407 public static boolean siteHasSitePermission(Site site,String permission) { | |
408 return hasSitePermission(site,permission); | |
409 } | |
410 | |
411 private static boolean hasSiteDefaultPermission(Site site,String permission) { | |
412 return site.hasTags(null,null, | |
413 "label='site_default_permission:" + encode(permission) + "'" | |
414 ); | |
415 } | |
416 | |
417 public static void addSitePermission(Site site,String permission,String group) { | |
418 dbCheck(site); | |
419 if( !hasSitePermission(site,permission) ) | |
420 site.addTag( null, null, "site_permission:" + permission ); | |
421 site.addTag( null, null, "site_permission:" + permission + ":" + group ); | |
422 } | |
423 | |
424 public static void addSiteDefaultPermission(Site site,String permission,String group) { | |
425 dbCheck(site); | |
426 if( !hasSiteDefaultPermission(site,permission) ) | |
427 site.addTag( null, null, "site_default_permission:" + permission ); | |
428 site.addTag( null, null, "site_default_permission:" + permission + ":" + group ); | |
429 } | |
430 | |
431 public static void removeSitePermission(Site site,String permission,String group) { | |
432 dbCheck(site); | |
433 site.deleteTags(null,null, | |
434 "label='site_permission:" + encode(permission) + ":" + encode(group) + "'" | |
435 ); | |
436 } | |
437 | |
438 public static void removeSitePermission(Site site,String permission) { | |
439 site.deleteTags(null,null, | |
440 "(label = 'site_permission:" + encode(permission) + "'" | |
441 + " or label like 'site_permission:" + encode(permission) + ":%')" | |
442 ); | |
443 } | |
444 | |
445 public static void removeSitePermissions(Site site) { | |
446 dbCheck(site); | |
447 site.deleteTags(null,null, | |
448 "label like 'site_permission:%'" | |
449 ); | |
450 } | |
451 | |
452 private static String sitePermissionLabel(Site site,String permission) { | |
453 if( hasSitePermission(site,permission) ) | |
454 return "site_permission:" + encode(permission); | |
455 else if( hasSiteDefaultPermission(site,permission) ) | |
456 return "site_default_permission:" + encode(permission); | |
457 else | |
458 return null; | |
459 } | |
460 | |
461 public static List<String> getGroupsWithSitePermission(Site site,String permission) { | |
462 String labelStart = sitePermissionLabel(site,permission); | |
463 if( labelStart == null ) | |
464 return Collections.emptyList(); | |
465 List<String> list = new ArrayList<String>(); | |
466 int i = labelStart.length(); | |
467 for( String label : site.findTagLabels( | |
468 "node_id is null and user_id is null and label like '" + labelStart + ":%'" | |
469 ) ) { | |
470 list.add( label.substring(i) ); | |
471 } | |
472 return list; | |
473 } | |
474 | |
475 public static boolean hasGroupsWithSitePermission(Site site,String permission) { | |
476 String labelStart = sitePermissionLabel(site,permission); | |
477 if( labelStart == null ) | |
478 return false; | |
479 return site.hasTags(null,null, | |
480 "label like '" + labelStart + ":%'" | |
481 ); | |
482 } | |
483 | |
484 public static boolean hasSitePermission(Site site,Person person,String permission) { | |
485 String labelStart = sitePermissionLabel(site,permission); | |
486 if( labelStart == null ) | |
487 return false; | |
488 String s = "label='" + labelStart + ":"; | |
489 List<String> groups = getPersonGroups(person); | |
490 for( String group : groups ) { | |
491 if( site.hasTags(null,null, s + encode(group) + "'" ) ) | |
492 return true; | |
493 } | |
494 return false; | |
495 } | |
496 | |
497 public static boolean hasSitePermission(Site site,String group,String permission) { | |
498 String labelStart = sitePermissionLabel(site,permission); | |
499 if( labelStart == null ) | |
500 return false; | |
501 return site.hasTags(null,null, | |
502 "label='" + labelStart + ":" + encode(group) + "'" | |
503 ); | |
504 } | |
505 | |
506 public static boolean hasSiteDefaultPermission(Site site,String group,String permission) { | |
507 return hasSiteDefaultPermission(site,permission) && site.hasTags(null,null, | |
508 "label='site_default_permission:" + encode(permission) + ":" + encode(group) + "'" | |
509 ); | |
510 } | |
511 | |
512 public static List<User> getUsersWithSitePermission(Site site,String permission) { | |
513 String labelStart = sitePermissionLabel(site,permission); | |
514 if (labelStart == null) | |
515 return Collections.emptyList(); | |
516 if (hasSitePermission(site,ANYONE_GROUP,permission)) | |
517 return site.getUsers(null); | |
518 else if (hasSitePermission(site,REGISTERED_GROUP,permission)) | |
519 return site.getUsers("registered is not null"); | |
520 labelStart += ":"; | |
521 int i = labelStart.length(); | |
522 return site.findTagUsers( | |
523 "node_id is null and user_id is not null and label in (" | |
524 + "select 'group:' || substring(label," + (i+1) + ") from tag where node is null and user_id is null and label like '" + labelStart + "%'" | |
525 +")" | |
526 ); | |
527 } | |
528 | |
529 | |
530 private static final ListenerList<Site> groupChangeListeners = new ListenerList<Site>(); | |
531 | |
532 public static void addGroupChangeListener(final Listener<Site> listener) { | |
533 groupChangeListeners.add(listener); | |
534 } | |
535 | |
536 private static final ListenerList<Site> permissionChangeListeners = new ListenerList<Site>(); | |
537 | |
538 public static void addPermissionChangeListener(final Listener<Site> listener) { | |
539 permissionChangeListeners.add(listener); | |
540 } | |
541 | |
542 } |