Mercurial Hosting > nabble
annotate src/nabble/view/lib/Permissions.java @ 62:4674ed7d56df default tip
remove n2
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sat, 30 Sep 2023 20:25:29 -0600 |
parents | aba8ed4c8a06 |
children |
rev | line source |
---|---|
0 | 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 AUTHOR_GROUP = "Authors"; | |
222 public static final String ADMINISTRATORS_GROUP = "Administrators"; | |
223 | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
224 public static List<String> getPersonGroups(User user) { |
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
225 if( user==null || !user.isRegistered() ) |
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
226 return new ArrayList<String>(); |
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
227 List<String> groups = getGroups(user); |
0 | 228 groups.add(ANYONE_GROUP); |
229 return groups; | |
230 } | |
231 | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
232 public static boolean hasPermission(Node permissionNode,Node targetNode,User user,String permission) { |
0 | 233 Person owner = targetNode.getOwner(); |
234 Site site = permissionNode.getSite(); | |
235 permissionNode = getPermissionNode(permissionNode,permission); | |
236 if( permissionNode == null && !siteHasPermission(site,permission) ) | |
237 return false; | |
238 String s = "label='permission:" + encode(permission) + ":"; | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
239 List<String> groups = getPersonGroups(user); |
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
240 if( owner.equals(user) ) |
0 | 241 groups.add(AUTHOR_GROUP); |
242 for( String group : groups ) { | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
243 if( site.hasTags(permissionNode,null, s + encode(group) + "'" ) ) { |
0 | 244 return true; |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
245 } |
0 | 246 } |
247 return false; | |
248 } | |
249 | |
250 public static boolean hasPermission(Node node,String group,String permission) { | |
251 Site site = node.getSite(); | |
252 node = getPermissionNode(node,permission); | |
253 if( node == null && !siteHasPermission(site,permission) ) | |
254 return false; | |
255 return hasPermission(site,node,group,permission); | |
256 } | |
257 | |
258 private static boolean hasPermission(Site site,Node node,String group,String permission) { | |
259 return site.hasTags(node,null, | |
260 "label='permission:" + encode(permission) + ":" + encode(group) + "'" | |
261 ); | |
262 } | |
263 | |
264 public static boolean hasPermission(Site site,String group,String permission) { | |
265 return siteHasPermission(site,permission) && site.hasTags(null,null, | |
266 "label='permission:" + encode(permission) + ":" + encode(group) + "'" | |
267 ); | |
268 } | |
269 | |
270 public static List<User> getUsersWithPermission(Node node,String permission) { | |
271 Site site = node.getSite(); | |
272 node = getPermissionNode(node,permission); | |
273 if( node == null && !siteHasPermission(site,permission) ) | |
274 return Collections.emptyList(); | |
275 if (hasPermission(site, node, ANYONE_GROUP,permission)) | |
276 return site.getUsers("registered is not null"); | |
277 String labelStart = "permission:" + encode(permission) + ":"; | |
278 int i = labelStart.length(); | |
279 return site.findTagUsers( | |
280 "node_id is null and user_id is not null and label in (" | |
281 + "select 'group:' || substring(label," + (i+1) + ") from tag where " + query(node) + " and user_id is null and label like '" + labelStart + "%'" | |
282 +")" | |
283 ); | |
284 } | |
285 | |
286 | |
287 public static final String VIEW_PERMISSION = "View"; | |
288 | |
289 public static boolean isPrivate(Node node) { | |
290 return getPrivateNode(node) != null; | |
291 } | |
292 | |
293 public static boolean canBeViewedByParentViewers(Node node) { | |
294 if( node.getKind() != Node.Kind.APP ) | |
295 return true; | |
296 if( !nodeHasPermission(node,VIEW_PERMISSION) ) | |
297 return true; | |
298 Node parent = node.getParent(); | |
299 if( parent != null ) | |
300 parent = getPrivateNode(parent); | |
301 if( parent == null && !siteHasPermission(node.getSite(),VIEW_PERMISSION) ) | |
302 return !isPrivate(node); | |
303 return !node.getSite().hasTags(parent,null, | |
304 "label like 'permission:View:%'" | |
305 +" and label not in (select label from tag where node_id=" + node.getId() + " and user_id is null and label like 'permission:View:%')" | |
306 ); | |
307 } | |
308 | |
309 public static final Filter<Node> canBeViewedByParentViewersFilter = new Filter<Node>() { | |
310 public boolean ok(Node node) { | |
311 return canBeViewedByParentViewers(node); | |
312 } | |
313 }; | |
314 | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
315 public static boolean canBeViewedByPerson(Node node,User user) { |
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
316 if( user != null ) { |
0 | 317 if( isSysAdmin(user) ) |
318 return true; | |
319 if( isInGroup(user,ADMINISTRATORS_GROUP) ) | |
320 return true; | |
321 } | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
322 if( node.getSite().getRootNode().getOwner().equals(user) ) |
0 | 323 return true; |
324 Node permissionNode = node.getApp(); | |
325 if( permissionNode==null ) | |
326 permissionNode = node.getSite().getRootNode(); | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
327 return hasPermission(permissionNode,node,user,VIEW_PERMISSION); |
0 | 328 } |
329 | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
330 public static final Filter<Node> canBeViewedByPersonFilter(final User user) { |
0 | 331 return new Filter<Node>() { |
332 public boolean ok(Node node) { | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
333 return canBeViewedByPerson(node,user); |
0 | 334 } |
335 }; | |
336 } | |
337 | |
338 public static Node getPrivateNode(Node node) { | |
339 node = getPermissionNode(node,VIEW_PERMISSION); | |
340 return node==null || hasPermission(node.getSite(),node,ANYONE_GROUP,VIEW_PERMISSION) ? null : node; | |
341 } | |
342 | |
343 public static Node getPrivateNodeForSearch(Node node) { | |
344 node = getPrivateNode(node); | |
345 while( node != null && canBeViewedByParentViewers(node) ) { | |
346 node = getPrivateNode(node.getParent()); | |
347 } | |
348 return node; | |
349 } | |
350 | |
351 // Banning ------------------------------------------------------ | |
352 | |
353 public static boolean isBanned(User user) { | |
354 return user.getSite().hasTags(null,user,"label='banned'"); | |
355 } | |
356 | |
357 public static void ban(User user) { | |
358 user.getSite().addTag(null, user, "banned"); | |
359 } | |
360 | |
361 public static void unban(User user) { | |
362 user.getSite().deleteTags(null,user,"label='banned'"); | |
363 } | |
364 | |
365 public static List<User> getBannedUsers(Site site) { | |
366 return site.findTagUsers( | |
367 "node_id is null and user_id is not null and label='banned'" | |
368 ); | |
369 } | |
370 | |
371 | |
372 | |
373 private static final Set<String> sysadmins = Init.get("sysadmins",Collections.<String>emptySet()); | |
374 | |
375 public static boolean isSysAdmin(User user) { | |
376 return sysadmins.contains(user.getEmail()); | |
377 } | |
378 | |
379 | |
380 // site permissions | |
381 | |
382 public static void addSitePermission(Site site,String permission) { | |
383 dbCheck(site); | |
384 site.addTag( null, null, "site_permission:" + permission ); | |
385 } | |
386 | |
387 public static void addSiteDefaultPermission(Site site,String permission) { | |
388 dbCheck(site); | |
389 site.addTag( null, null, "site_default_permission:" + permission ); | |
390 } | |
391 | |
392 private static boolean hasSitePermission(Site site,String permission) { | |
393 return site.hasTags(null,null, | |
394 "label='site_permission:" + encode(permission) + "'" | |
395 ); | |
396 } | |
397 | |
398 public static boolean siteHasSitePermission(Site site,String permission) { | |
399 return hasSitePermission(site,permission); | |
400 } | |
401 | |
402 private static boolean hasSiteDefaultPermission(Site site,String permission) { | |
403 return site.hasTags(null,null, | |
404 "label='site_default_permission:" + encode(permission) + "'" | |
405 ); | |
406 } | |
407 | |
408 public static void addSitePermission(Site site,String permission,String group) { | |
409 dbCheck(site); | |
410 if( !hasSitePermission(site,permission) ) | |
411 site.addTag( null, null, "site_permission:" + permission ); | |
412 site.addTag( null, null, "site_permission:" + permission + ":" + group ); | |
413 } | |
414 | |
415 public static void addSiteDefaultPermission(Site site,String permission,String group) { | |
416 dbCheck(site); | |
417 if( !hasSiteDefaultPermission(site,permission) ) | |
418 site.addTag( null, null, "site_default_permission:" + permission ); | |
419 site.addTag( null, null, "site_default_permission:" + permission + ":" + group ); | |
420 } | |
421 | |
422 public static void removeSitePermission(Site site,String permission,String group) { | |
423 dbCheck(site); | |
424 site.deleteTags(null,null, | |
425 "label='site_permission:" + encode(permission) + ":" + encode(group) + "'" | |
426 ); | |
427 } | |
428 | |
429 public static void removeSitePermission(Site site,String permission) { | |
430 site.deleteTags(null,null, | |
431 "(label = 'site_permission:" + encode(permission) + "'" | |
432 + " or label like 'site_permission:" + encode(permission) + ":%')" | |
433 ); | |
434 } | |
435 | |
436 public static void removeSitePermissions(Site site) { | |
437 dbCheck(site); | |
438 site.deleteTags(null,null, | |
439 "label like 'site_permission:%'" | |
440 ); | |
441 } | |
442 | |
443 private static String sitePermissionLabel(Site site,String permission) { | |
444 if( hasSitePermission(site,permission) ) | |
445 return "site_permission:" + encode(permission); | |
446 else if( hasSiteDefaultPermission(site,permission) ) | |
447 return "site_default_permission:" + encode(permission); | |
448 else | |
449 return null; | |
450 } | |
451 | |
452 public static List<String> getGroupsWithSitePermission(Site site,String permission) { | |
453 String labelStart = sitePermissionLabel(site,permission); | |
454 if( labelStart == null ) | |
455 return Collections.emptyList(); | |
456 List<String> list = new ArrayList<String>(); | |
457 int i = labelStart.length(); | |
458 for( String label : site.findTagLabels( | |
459 "node_id is null and user_id is null and label like '" + labelStart + ":%'" | |
460 ) ) { | |
461 list.add( label.substring(i) ); | |
462 } | |
463 return list; | |
464 } | |
465 | |
466 public static boolean hasGroupsWithSitePermission(Site site,String permission) { | |
467 String labelStart = sitePermissionLabel(site,permission); | |
468 if( labelStart == null ) | |
469 return false; | |
470 return site.hasTags(null,null, | |
471 "label like '" + labelStart + ":%'" | |
472 ); | |
473 } | |
474 | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
475 public static boolean hasSitePermission(Site site,User user,String permission) { |
0 | 476 String labelStart = sitePermissionLabel(site,permission); |
477 if( labelStart == null ) | |
478 return false; | |
479 String s = "label='" + labelStart + ":"; | |
19
18cf4872fd7f
remove anonymous posting
Franklin Schmidt <fschmidt@gmail.com>
parents:
0
diff
changeset
|
480 List<String> groups = getPersonGroups(user); |
0 | 481 for( String group : groups ) { |
482 if( site.hasTags(null,null, s + encode(group) + "'" ) ) | |
483 return true; | |
484 } | |
485 return false; | |
486 } | |
487 | |
488 public static boolean hasSitePermission(Site site,String group,String permission) { | |
489 String labelStart = sitePermissionLabel(site,permission); | |
490 if( labelStart == null ) | |
491 return false; | |
492 return site.hasTags(null,null, | |
493 "label='" + labelStart + ":" + encode(group) + "'" | |
494 ); | |
495 } | |
496 | |
497 public static boolean hasSiteDefaultPermission(Site site,String group,String permission) { | |
498 return hasSiteDefaultPermission(site,permission) && site.hasTags(null,null, | |
499 "label='site_default_permission:" + encode(permission) + ":" + encode(group) + "'" | |
500 ); | |
501 } | |
502 | |
503 private static final ListenerList<Site> groupChangeListeners = new ListenerList<Site>(); | |
504 | |
505 public static void addGroupChangeListener(final Listener<Site> listener) { | |
506 groupChangeListeners.add(listener); | |
507 } | |
508 | |
509 private static final ListenerList<Site> permissionChangeListeners = new ListenerList<Site>(); | |
510 | |
511 public static void addPermissionChangeListener(final Listener<Site> listener) { | |
512 permissionChangeListeners.add(listener); | |
513 } | |
514 | |
515 } |