service.go raw
1 package main
2
3 import (
4 "context"
5 "errors"
6 "time"
7
8 "google.golang.org/grpc/codes"
9 "google.golang.org/grpc/status"
10 "next.orly.dev/pkg/lol/log"
11
12 "next.orly.dev/pkg/acl"
13 "next.orly.dev/pkg/database"
14 orlyaclv1 "next.orly.dev/pkg/proto/orlyacl/v1"
15 orlydbv1 "next.orly.dev/pkg/proto/orlydb/v1"
16 )
17
18 // ACLService implements the orlyaclv1.ACLServiceServer interface.
19 type ACLService struct {
20 orlyaclv1.UnimplementedACLServiceServer
21 cfg *Config
22 db database.Database
23 ready bool
24 }
25
26 // NewACLService creates a new ACL service.
27 func NewACLService(cfg *Config, db database.Database) *ACLService {
28 return &ACLService{
29 cfg: cfg,
30 db: db,
31 ready: false, // Not ready until Configure completes
32 }
33 }
34
35 // SetReady marks the service as ready (or not ready).
36 func (s *ACLService) SetReady(ready bool) {
37 s.ready = ready
38 if ready {
39 log.I.F("ACL service is now ready")
40 }
41 }
42
43 // === Core ACL Methods ===
44
45 func (s *ACLService) GetAccessLevel(ctx context.Context, req *orlyaclv1.AccessLevelRequest) (*orlyaclv1.AccessLevelResponse, error) {
46 level := acl.Registry.GetAccessLevel(req.Pubkey, req.Address)
47 return &orlyaclv1.AccessLevelResponse{Level: level}, nil
48 }
49
50 func (s *ACLService) CheckPolicy(ctx context.Context, req *orlyaclv1.PolicyCheckRequest) (*orlyaclv1.PolicyCheckResponse, error) {
51 ev := orlydbv1.ProtoToEvent(req.Event)
52 allowed, err := acl.Registry.CheckPolicy(ev)
53 resp := &orlyaclv1.PolicyCheckResponse{Allowed: allowed}
54 if err != nil {
55 resp.Error = err.Error()
56 }
57 return resp, nil
58 }
59
60 func (s *ACLService) GetACLInfo(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ACLInfoResponse, error) {
61 name, description, documentation := acl.Registry.GetACLInfo()
62 return &orlyaclv1.ACLInfoResponse{
63 Name: name,
64 Description: description,
65 Documentation: documentation,
66 }, nil
67 }
68
69 func (s *ACLService) GetMode(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ModeResponse, error) {
70 return &orlyaclv1.ModeResponse{Mode: acl.Registry.Type()}, nil
71 }
72
73 func (s *ACLService) Ready(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ReadyResponse, error) {
74 // Check if service is fully configured and ready
75 return &orlyaclv1.ReadyResponse{Ready: s.ready}, nil
76 }
77
78 // === Follows ACL Methods ===
79
80 func (s *ACLService) GetThrottleDelay(ctx context.Context, req *orlyaclv1.ThrottleDelayRequest) (*orlyaclv1.ThrottleDelayResponse, error) {
81 // Get the active ACL and check if it's Follows
82 for _, i := range acl.Registry.ACLs() {
83 if i.Type() == "follows" {
84 if follows, ok := i.(*acl.Follows); ok {
85 delay := follows.GetThrottleDelay(req.Pubkey, req.Ip)
86 return &orlyaclv1.ThrottleDelayResponse{DelayMs: delay.Milliseconds()}, nil
87 }
88 }
89 }
90 return &orlyaclv1.ThrottleDelayResponse{DelayMs: 0}, nil
91 }
92
93 func (s *ACLService) AddFollow(ctx context.Context, req *orlyaclv1.AddFollowRequest) (*orlyaclv1.Empty, error) {
94 acl.Registry.AddFollow(req.Pubkey)
95 return &orlyaclv1.Empty{}, nil
96 }
97
98 func (s *ACLService) GetFollowedPubkeys(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.FollowedPubkeysResponse, error) {
99 for _, i := range acl.Registry.ACLs() {
100 if i.Type() == "follows" {
101 if follows, ok := i.(*acl.Follows); ok {
102 pubkeys := follows.GetFollowedPubkeys()
103 return &orlyaclv1.FollowedPubkeysResponse{Pubkeys: pubkeys}, nil
104 }
105 }
106 }
107 return &orlyaclv1.FollowedPubkeysResponse{}, nil
108 }
109
110 func (s *ACLService) GetAdminRelays(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.AdminRelaysResponse, error) {
111 for _, i := range acl.Registry.ACLs() {
112 if i.Type() == "follows" {
113 if follows, ok := i.(*acl.Follows); ok {
114 urls := follows.AdminRelays()
115 return &orlyaclv1.AdminRelaysResponse{Urls: urls}, nil
116 }
117 }
118 }
119 return &orlyaclv1.AdminRelaysResponse{}, nil
120 }
121
122 // === Managed ACL Methods ===
123
124 func (s *ACLService) BanPubkey(ctx context.Context, req *orlyaclv1.BanPubkeyRequest) (*orlyaclv1.Empty, error) {
125 managed := s.getManagedACL()
126 if managed == nil {
127 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
128 }
129 managedACL := managed.GetManagedACL()
130 if managedACL == nil {
131 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
132 }
133 if err := managedACL.SaveBannedPubkey(req.Pubkey, req.Reason); err != nil {
134 return nil, status.Errorf(codes.Internal, "failed to ban pubkey: %v", err)
135 }
136 return &orlyaclv1.Empty{}, nil
137 }
138
139 func (s *ACLService) UnbanPubkey(ctx context.Context, req *orlyaclv1.PubkeyRequest) (*orlyaclv1.Empty, error) {
140 managed := s.getManagedACL()
141 if managed == nil {
142 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
143 }
144 managedACL := managed.GetManagedACL()
145 if managedACL == nil {
146 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
147 }
148 if err := managedACL.RemoveBannedPubkey(req.Pubkey); err != nil {
149 return nil, status.Errorf(codes.Internal, "failed to unban pubkey: %v", err)
150 }
151 return &orlyaclv1.Empty{}, nil
152 }
153
154 func (s *ACLService) ListBannedPubkeys(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListBannedPubkeysResponse, error) {
155 managed := s.getManagedACL()
156 if managed == nil {
157 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
158 }
159 managedACL := managed.GetManagedACL()
160 if managedACL == nil {
161 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
162 }
163 banned, err := managedACL.ListBannedPubkeys()
164 if err != nil {
165 return nil, status.Errorf(codes.Internal, "failed to list banned pubkeys: %v", err)
166 }
167 resp := &orlyaclv1.ListBannedPubkeysResponse{}
168 for _, b := range banned {
169 resp.Pubkeys = append(resp.Pubkeys, &orlyaclv1.BannedPubkey{
170 Pubkey: b.Pubkey,
171 Reason: b.Reason,
172 Added: b.Added.Unix(),
173 })
174 }
175 return resp, nil
176 }
177
178 func (s *ACLService) AllowPubkey(ctx context.Context, req *orlyaclv1.AllowPubkeyRequest) (*orlyaclv1.Empty, error) {
179 managed := s.getManagedACL()
180 if managed == nil {
181 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
182 }
183 managedACL := managed.GetManagedACL()
184 if managedACL == nil {
185 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
186 }
187 if err := managedACL.SaveAllowedPubkey(req.Pubkey, req.Reason); err != nil {
188 return nil, status.Errorf(codes.Internal, "failed to allow pubkey: %v", err)
189 }
190 return &orlyaclv1.Empty{}, nil
191 }
192
193 func (s *ACLService) DisallowPubkey(ctx context.Context, req *orlyaclv1.PubkeyRequest) (*orlyaclv1.Empty, error) {
194 managed := s.getManagedACL()
195 if managed == nil {
196 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
197 }
198 managedACL := managed.GetManagedACL()
199 if managedACL == nil {
200 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
201 }
202 if err := managedACL.RemoveAllowedPubkey(req.Pubkey); err != nil {
203 return nil, status.Errorf(codes.Internal, "failed to disallow pubkey: %v", err)
204 }
205 return &orlyaclv1.Empty{}, nil
206 }
207
208 func (s *ACLService) ListAllowedPubkeys(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListAllowedPubkeysResponse, error) {
209 managed := s.getManagedACL()
210 if managed == nil {
211 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
212 }
213 managedACL := managed.GetManagedACL()
214 if managedACL == nil {
215 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
216 }
217 allowed, err := managedACL.ListAllowedPubkeys()
218 if err != nil {
219 return nil, status.Errorf(codes.Internal, "failed to list allowed pubkeys: %v", err)
220 }
221 resp := &orlyaclv1.ListAllowedPubkeysResponse{}
222 for _, a := range allowed {
223 resp.Pubkeys = append(resp.Pubkeys, &orlyaclv1.AllowedPubkey{
224 Pubkey: a.Pubkey,
225 Reason: a.Reason,
226 Added: a.Added.Unix(),
227 })
228 }
229 return resp, nil
230 }
231
232 func (s *ACLService) BanEvent(ctx context.Context, req *orlyaclv1.BanEventRequest) (*orlyaclv1.Empty, error) {
233 managed := s.getManagedACL()
234 if managed == nil {
235 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
236 }
237 managedACL := managed.GetManagedACL()
238 if managedACL == nil {
239 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
240 }
241 if err := managedACL.SaveBannedEvent(req.EventId, req.Reason); err != nil {
242 return nil, status.Errorf(codes.Internal, "failed to ban event: %v", err)
243 }
244 return &orlyaclv1.Empty{}, nil
245 }
246
247 func (s *ACLService) UnbanEvent(ctx context.Context, req *orlyaclv1.EventRequest) (*orlyaclv1.Empty, error) {
248 managed := s.getManagedACL()
249 if managed == nil {
250 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
251 }
252 managedACL := managed.GetManagedACL()
253 if managedACL == nil {
254 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
255 }
256 if err := managedACL.RemoveBannedEvent(req.EventId); err != nil {
257 return nil, status.Errorf(codes.Internal, "failed to unban event: %v", err)
258 }
259 return &orlyaclv1.Empty{}, nil
260 }
261
262 func (s *ACLService) ListBannedEvents(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListBannedEventsResponse, error) {
263 managed := s.getManagedACL()
264 if managed == nil {
265 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
266 }
267 managedACL := managed.GetManagedACL()
268 if managedACL == nil {
269 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
270 }
271 banned, err := managedACL.ListBannedEvents()
272 if err != nil {
273 return nil, status.Errorf(codes.Internal, "failed to list banned events: %v", err)
274 }
275 resp := &orlyaclv1.ListBannedEventsResponse{}
276 for _, b := range banned {
277 resp.Events = append(resp.Events, &orlyaclv1.BannedEvent{
278 EventId: b.ID,
279 Reason: b.Reason,
280 Added: b.Added.Unix(),
281 })
282 }
283 return resp, nil
284 }
285
286 func (s *ACLService) AllowEvent(ctx context.Context, req *orlyaclv1.BanEventRequest) (*orlyaclv1.Empty, error) {
287 managed := s.getManagedACL()
288 if managed == nil {
289 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
290 }
291 managedACL := managed.GetManagedACL()
292 if managedACL == nil {
293 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
294 }
295 if err := managedACL.SaveAllowedEvent(req.EventId, req.Reason); err != nil {
296 return nil, status.Errorf(codes.Internal, "failed to allow event: %v", err)
297 }
298 return &orlyaclv1.Empty{}, nil
299 }
300
301 func (s *ACLService) DisallowEvent(ctx context.Context, req *orlyaclv1.EventRequest) (*orlyaclv1.Empty, error) {
302 managed := s.getManagedACL()
303 if managed == nil {
304 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
305 }
306 managedACL := managed.GetManagedACL()
307 if managedACL == nil {
308 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
309 }
310 if err := managedACL.RemoveAllowedEvent(req.EventId); err != nil {
311 return nil, status.Errorf(codes.Internal, "failed to disallow event: %v", err)
312 }
313 return &orlyaclv1.Empty{}, nil
314 }
315
316 func (s *ACLService) ListAllowedEvents(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListAllowedEventsResponse, error) {
317 managed := s.getManagedACL()
318 if managed == nil {
319 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
320 }
321 managedACL := managed.GetManagedACL()
322 if managedACL == nil {
323 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
324 }
325 allowed, err := managedACL.ListAllowedEvents()
326 if err != nil {
327 return nil, status.Errorf(codes.Internal, "failed to list allowed events: %v", err)
328 }
329 resp := &orlyaclv1.ListAllowedEventsResponse{}
330 for _, a := range allowed {
331 resp.Events = append(resp.Events, &orlyaclv1.AllowedEvent{
332 EventId: a.ID,
333 Reason: a.Reason,
334 Added: a.Added.Unix(),
335 })
336 }
337 return resp, nil
338 }
339
340 func (s *ACLService) BlockIP(ctx context.Context, req *orlyaclv1.BlockIPRequest) (*orlyaclv1.Empty, error) {
341 managed := s.getManagedACL()
342 if managed == nil {
343 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
344 }
345 managedACL := managed.GetManagedACL()
346 if managedACL == nil {
347 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
348 }
349 if err := managedACL.SaveBlockedIP(req.Ip, req.Reason); err != nil {
350 return nil, status.Errorf(codes.Internal, "failed to block IP: %v", err)
351 }
352 return &orlyaclv1.Empty{}, nil
353 }
354
355 func (s *ACLService) UnblockIP(ctx context.Context, req *orlyaclv1.IPRequest) (*orlyaclv1.Empty, error) {
356 managed := s.getManagedACL()
357 if managed == nil {
358 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
359 }
360 managedACL := managed.GetManagedACL()
361 if managedACL == nil {
362 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
363 }
364 if err := managedACL.RemoveBlockedIP(req.Ip); err != nil {
365 return nil, status.Errorf(codes.Internal, "failed to unblock IP: %v", err)
366 }
367 return &orlyaclv1.Empty{}, nil
368 }
369
370 func (s *ACLService) ListBlockedIPs(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListBlockedIPsResponse, error) {
371 managed := s.getManagedACL()
372 if managed == nil {
373 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
374 }
375 managedACL := managed.GetManagedACL()
376 if managedACL == nil {
377 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
378 }
379 blocked, err := managedACL.ListBlockedIPs()
380 if err != nil {
381 return nil, status.Errorf(codes.Internal, "failed to list blocked IPs: %v", err)
382 }
383 resp := &orlyaclv1.ListBlockedIPsResponse{}
384 for _, b := range blocked {
385 resp.Ips = append(resp.Ips, &orlyaclv1.BlockedIP{
386 Ip: b.IP,
387 Reason: b.Reason,
388 Added: b.Added.Unix(),
389 })
390 }
391 return resp, nil
392 }
393
394 func (s *ACLService) AllowKind(ctx context.Context, req *orlyaclv1.AllowKindRequest) (*orlyaclv1.Empty, error) {
395 managed := s.getManagedACL()
396 if managed == nil {
397 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
398 }
399 managedACL := managed.GetManagedACL()
400 if managedACL == nil {
401 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
402 }
403 if err := managedACL.SaveAllowedKind(int(req.Kind)); err != nil {
404 return nil, status.Errorf(codes.Internal, "failed to allow kind: %v", err)
405 }
406 return &orlyaclv1.Empty{}, nil
407 }
408
409 func (s *ACLService) DisallowKind(ctx context.Context, req *orlyaclv1.KindRequest) (*orlyaclv1.Empty, error) {
410 managed := s.getManagedACL()
411 if managed == nil {
412 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
413 }
414 managedACL := managed.GetManagedACL()
415 if managedACL == nil {
416 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
417 }
418 if err := managedACL.RemoveAllowedKind(int(req.Kind)); err != nil {
419 return nil, status.Errorf(codes.Internal, "failed to disallow kind: %v", err)
420 }
421 return &orlyaclv1.Empty{}, nil
422 }
423
424 func (s *ACLService) ListAllowedKinds(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListAllowedKindsResponse, error) {
425 managed := s.getManagedACL()
426 if managed == nil {
427 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
428 }
429 managedACL := managed.GetManagedACL()
430 if managedACL == nil {
431 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL database not available")
432 }
433 kinds, err := managedACL.ListAllowedKinds()
434 if err != nil {
435 return nil, status.Errorf(codes.Internal, "failed to list allowed kinds: %v", err)
436 }
437 resp := &orlyaclv1.ListAllowedKindsResponse{}
438 for _, k := range kinds {
439 resp.Kinds = append(resp.Kinds, int32(k))
440 }
441 return resp, nil
442 }
443
444 func (s *ACLService) UpdatePeerAdmins(ctx context.Context, req *orlyaclv1.UpdatePeerAdminsRequest) (*orlyaclv1.Empty, error) {
445 managed := s.getManagedACL()
446 if managed == nil {
447 return nil, status.Errorf(codes.FailedPrecondition, "managed ACL not available")
448 }
449 managed.UpdatePeerAdmins(req.PeerPubkeys)
450 return &orlyaclv1.Empty{}, nil
451 }
452
453 // === Curating ACL Methods ===
454
455 func (s *ACLService) TrustPubkey(ctx context.Context, req *orlyaclv1.TrustPubkeyRequest) (*orlyaclv1.Empty, error) {
456 curating := s.getCuratingACL()
457 if curating == nil {
458 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
459 }
460 if err := curating.TrustPubkey(req.Pubkey, req.Note); err != nil {
461 return nil, status.Errorf(codes.Internal, "failed to trust pubkey: %v", err)
462 }
463 return &orlyaclv1.Empty{}, nil
464 }
465
466 func (s *ACLService) UntrustPubkey(ctx context.Context, req *orlyaclv1.PubkeyRequest) (*orlyaclv1.Empty, error) {
467 curating := s.getCuratingACL()
468 if curating == nil {
469 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
470 }
471 if err := curating.UntrustPubkey(req.Pubkey); err != nil {
472 return nil, status.Errorf(codes.Internal, "failed to untrust pubkey: %v", err)
473 }
474 return &orlyaclv1.Empty{}, nil
475 }
476
477 func (s *ACLService) ListTrustedPubkeys(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListTrustedPubkeysResponse, error) {
478 curating := s.getCuratingACL()
479 if curating == nil {
480 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
481 }
482 curatingACL := curating.GetCuratingACL()
483 if curatingACL == nil {
484 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
485 }
486 trusted, err := curatingACL.ListTrustedPubkeys()
487 if err != nil {
488 return nil, status.Errorf(codes.Internal, "failed to list trusted pubkeys: %v", err)
489 }
490 resp := &orlyaclv1.ListTrustedPubkeysResponse{}
491 for _, t := range trusted {
492 resp.Pubkeys = append(resp.Pubkeys, &orlyaclv1.TrustedPubkey{
493 Pubkey: t.Pubkey,
494 Note: t.Note,
495 Added: t.Added.Unix(),
496 })
497 }
498 return resp, nil
499 }
500
501 func (s *ACLService) BlacklistPubkey(ctx context.Context, req *orlyaclv1.BlacklistPubkeyRequest) (*orlyaclv1.Empty, error) {
502 curating := s.getCuratingACL()
503 if curating == nil {
504 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
505 }
506 if err := curating.BlacklistPubkey(req.Pubkey, req.Reason); err != nil {
507 return nil, status.Errorf(codes.Internal, "failed to blacklist pubkey: %v", err)
508 }
509 return &orlyaclv1.Empty{}, nil
510 }
511
512 func (s *ACLService) UnblacklistPubkey(ctx context.Context, req *orlyaclv1.PubkeyRequest) (*orlyaclv1.Empty, error) {
513 curating := s.getCuratingACL()
514 if curating == nil {
515 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
516 }
517 if err := curating.UnblacklistPubkey(req.Pubkey); err != nil {
518 return nil, status.Errorf(codes.Internal, "failed to unblacklist pubkey: %v", err)
519 }
520 return &orlyaclv1.Empty{}, nil
521 }
522
523 func (s *ACLService) ListBlacklistedPubkeys(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListBlacklistedPubkeysResponse, error) {
524 curating := s.getCuratingACL()
525 if curating == nil {
526 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
527 }
528 curatingACL := curating.GetCuratingACL()
529 if curatingACL == nil {
530 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
531 }
532 blacklisted, err := curatingACL.ListBlacklistedPubkeys()
533 if err != nil {
534 return nil, status.Errorf(codes.Internal, "failed to list blacklisted pubkeys: %v", err)
535 }
536 resp := &orlyaclv1.ListBlacklistedPubkeysResponse{}
537 for _, b := range blacklisted {
538 resp.Pubkeys = append(resp.Pubkeys, &orlyaclv1.BlacklistedPubkey{
539 Pubkey: b.Pubkey,
540 Reason: b.Reason,
541 Added: b.Added.Unix(),
542 })
543 }
544 return resp, nil
545 }
546
547 func (s *ACLService) MarkSpam(ctx context.Context, req *orlyaclv1.MarkSpamRequest) (*orlyaclv1.Empty, error) {
548 curating := s.getCuratingACL()
549 if curating == nil {
550 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
551 }
552 curatingACL := curating.GetCuratingACL()
553 if curatingACL == nil {
554 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
555 }
556 if err := curatingACL.MarkEventAsSpam(req.EventId, req.Pubkey, req.Reason); err != nil {
557 return nil, status.Errorf(codes.Internal, "failed to mark spam: %v", err)
558 }
559 return &orlyaclv1.Empty{}, nil
560 }
561
562 func (s *ACLService) UnmarkSpam(ctx context.Context, req *orlyaclv1.EventRequest) (*orlyaclv1.Empty, error) {
563 curating := s.getCuratingACL()
564 if curating == nil {
565 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
566 }
567 curatingACL := curating.GetCuratingACL()
568 if curatingACL == nil {
569 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
570 }
571 if err := curatingACL.UnmarkEventAsSpam(req.EventId); err != nil {
572 return nil, status.Errorf(codes.Internal, "failed to unmark spam: %v", err)
573 }
574 return &orlyaclv1.Empty{}, nil
575 }
576
577 func (s *ACLService) ListSpamEvents(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ListSpamEventsResponse, error) {
578 curating := s.getCuratingACL()
579 if curating == nil {
580 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
581 }
582 curatingACL := curating.GetCuratingACL()
583 if curatingACL == nil {
584 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
585 }
586 spam, err := curatingACL.ListSpamEvents()
587 if err != nil {
588 return nil, status.Errorf(codes.Internal, "failed to list spam events: %v", err)
589 }
590 resp := &orlyaclv1.ListSpamEventsResponse{}
591 for _, se := range spam {
592 resp.Events = append(resp.Events, &orlyaclv1.SpamEvent{
593 EventId: se.EventID,
594 Pubkey: se.Pubkey,
595 Reason: se.Reason,
596 Added: se.Added.Unix(),
597 })
598 }
599 return resp, nil
600 }
601
602 func (s *ACLService) RateLimitCheck(ctx context.Context, req *orlyaclv1.RateLimitCheckRequest) (*orlyaclv1.RateLimitCheckResponse, error) {
603 curating := s.getCuratingACL()
604 if curating == nil {
605 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
606 }
607 allowed, message, err := curating.RateLimitCheck(req.Pubkey, req.Ip)
608 if err != nil {
609 return nil, status.Errorf(codes.Internal, "failed to check rate limit: %v", err)
610 }
611 return &orlyaclv1.RateLimitCheckResponse{
612 Allowed: allowed,
613 Message: message,
614 }, nil
615 }
616
617 func (s *ACLService) ProcessConfigEvent(ctx context.Context, req *orlyaclv1.ConfigEventRequest) (*orlyaclv1.Empty, error) {
618 curating := s.getCuratingACL()
619 if curating == nil {
620 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
621 }
622 ev := orlydbv1.ProtoToEvent(req.Event)
623 if err := curating.ProcessConfigEvent(ev); err != nil {
624 return nil, status.Errorf(codes.Internal, "failed to process config event: %v", err)
625 }
626 return &orlyaclv1.Empty{}, nil
627 }
628
629 func (s *ACLService) GetCuratingConfig(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.CuratingConfig, error) {
630 curating := s.getCuratingACL()
631 if curating == nil {
632 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
633 }
634 config, err := curating.GetConfig()
635 if err != nil {
636 return nil, status.Errorf(codes.Internal, "failed to get config: %v", err)
637 }
638 resp := &orlyaclv1.CuratingConfig{
639 ConfigEventId: config.ConfigEventID,
640 ConfigPubkey: config.ConfigPubkey,
641 ConfiguredAt: config.ConfiguredAt,
642 DailyLimit: int32(config.DailyLimit),
643 IpDailyLimit: int32(config.IPDailyLimit),
644 FirstBanHours: int32(config.FirstBanHours),
645 SecondBanHours: int32(config.SecondBanHours),
646 KindCategories: config.KindCategories,
647 AllowedRanges: config.AllowedRanges,
648 }
649 for _, k := range config.AllowedKinds {
650 resp.AllowedKinds = append(resp.AllowedKinds, int32(k))
651 }
652 return resp, nil
653 }
654
655 func (s *ACLService) IsCuratingConfigured(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.BoolResponse, error) {
656 curating := s.getCuratingACL()
657 if curating == nil {
658 return &orlyaclv1.BoolResponse{Value: false}, nil
659 }
660 configured, err := curating.IsConfigured()
661 if err != nil {
662 return nil, status.Errorf(codes.Internal, "failed to check if configured: %v", err)
663 }
664 return &orlyaclv1.BoolResponse{Value: configured}, nil
665 }
666
667 func (s *ACLService) ListUnclassifiedUsers(ctx context.Context, req *orlyaclv1.PaginationRequest) (*orlyaclv1.ListUnclassifiedUsersResponse, error) {
668 curating := s.getCuratingACL()
669 if curating == nil {
670 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
671 }
672 curatingACL := curating.GetCuratingACL()
673 if curatingACL == nil {
674 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
675 }
676 // The underlying ListUnclassifiedUsers only takes limit, not offset
677 // We'll request limit+offset and skip the first offset items
678 limit := int(req.Limit)
679 offset := int(req.Offset)
680 if limit == 0 {
681 limit = 100 // Default limit
682 }
683 users, err := curatingACL.ListUnclassifiedUsers(limit + offset)
684 if err != nil {
685 return nil, status.Errorf(codes.Internal, "failed to list unclassified users: %v", err)
686 }
687 // Apply offset
688 if offset > 0 && len(users) > offset {
689 users = users[offset:]
690 } else if offset > 0 {
691 users = nil
692 }
693 // Apply limit
694 if limit > 0 && len(users) > limit {
695 users = users[:limit]
696 }
697 resp := &orlyaclv1.ListUnclassifiedUsersResponse{Total: int32(len(users))}
698 for _, u := range users {
699 resp.Users = append(resp.Users, &orlyaclv1.UnclassifiedUser{
700 Pubkey: u.Pubkey,
701 EventCount: int32(u.EventCount),
702 FirstSeen: u.LastEvent.Format("2006-01-02T15:04:05Z"),
703 })
704 }
705 return resp, nil
706 }
707
708 func (s *ACLService) GetEventsForPubkey(ctx context.Context, req *orlyaclv1.GetEventsForPubkeyRequest) (*orlyaclv1.EventsForPubkeyResponse, error) {
709 curating := s.getCuratingACL()
710 if curating == nil {
711 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
712 }
713 curatingACL := curating.GetCuratingACL()
714 if curatingACL == nil {
715 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
716 }
717 events, total, err := curatingACL.GetEventsForPubkey(req.Pubkey, int(req.Limit), int(req.Offset))
718 if err != nil {
719 return nil, status.Errorf(codes.Internal, "failed to get events for pubkey: %v", err)
720 }
721 resp := &orlyaclv1.EventsForPubkeyResponse{Total: int32(total)}
722 for _, ev := range events {
723 resp.Events = append(resp.Events, &orlyaclv1.EventSummary{
724 Id: ev.ID,
725 Kind: uint32(ev.Kind),
726 Content: []byte(ev.Content),
727 CreatedAt: ev.CreatedAt,
728 })
729 }
730 return resp, nil
731 }
732
733 func (s *ACLService) DeleteEventsForPubkey(ctx context.Context, req *orlyaclv1.DeleteEventsForPubkeyRequest) (*orlyaclv1.DeleteCountResponse, error) {
734 curating := s.getCuratingACL()
735 if curating == nil {
736 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
737 }
738 curatingACL := curating.GetCuratingACL()
739 if curatingACL == nil {
740 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
741 }
742 count, err := curatingACL.DeleteEventsForPubkey(req.Pubkey)
743 if err != nil {
744 return nil, status.Errorf(codes.Internal, "failed to delete events for pubkey: %v", err)
745 }
746 return &orlyaclv1.DeleteCountResponse{Count: int32(count)}, nil
747 }
748
749 func (s *ACLService) ScanAllPubkeys(ctx context.Context, req *orlyaclv1.Empty) (*orlyaclv1.ScanResultResponse, error) {
750 curating := s.getCuratingACL()
751 if curating == nil {
752 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL not available")
753 }
754 curatingACL := curating.GetCuratingACL()
755 if curatingACL == nil {
756 return nil, status.Errorf(codes.FailedPrecondition, "curating ACL database not available")
757 }
758 result, err := curatingACL.ScanAllPubkeys()
759 if err != nil {
760 return nil, status.Errorf(codes.Internal, "failed to scan all pubkeys: %v", err)
761 }
762 return &orlyaclv1.ScanResultResponse{
763 TotalPubkeys: int32(result.TotalPubkeys),
764 TotalEvents: int32(result.TotalEvents),
765 }, nil
766 }
767
768 // === Helper Methods ===
769
770 func (s *ACLService) getManagedACL() *acl.Managed {
771 for _, i := range acl.Registry.ACLs() {
772 if i.Type() == "managed" {
773 if managed, ok := i.(*acl.Managed); ok {
774 return managed
775 }
776 }
777 }
778 return nil
779 }
780
781 func (s *ACLService) getCuratingACL() *acl.Curating {
782 for _, i := range acl.Registry.ACLs() {
783 if i.Type() == "curating" {
784 if curating, ok := i.(*acl.Curating); ok {
785 return curating
786 }
787 }
788 }
789 return nil
790 }
791
792 // === Paid ACL Methods ===
793
794 func (s *ACLService) SubscribePubkey(ctx context.Context, req *orlyaclv1.SubscribeRequest) (*orlyaclv1.Empty, error) {
795 paid := s.getPaidACL()
796 if paid == nil {
797 return nil, status.Errorf(codes.FailedPrecondition, "paid ACL not available")
798 }
799 expiresAt := time.Unix(req.ExpiresAt, 0)
800 if err := paid.Subscribe(req.Pubkey, expiresAt, req.InvoiceHash, req.Alias); err != nil {
801 return nil, status.Errorf(codes.Internal, "failed to subscribe: %v", err)
802 }
803 return &orlyaclv1.Empty{}, nil
804 }
805
806 func (s *ACLService) UnsubscribePubkey(ctx context.Context, req *orlyaclv1.PubkeyRequest) (*orlyaclv1.Empty, error) {
807 paid := s.getPaidACL()
808 if paid == nil {
809 return nil, status.Errorf(codes.FailedPrecondition, "paid ACL not available")
810 }
811 if err := paid.Unsubscribe(req.Pubkey); err != nil {
812 return nil, status.Errorf(codes.Internal, "failed to unsubscribe: %v", err)
813 }
814 return &orlyaclv1.Empty{}, nil
815 }
816
817 func (s *ACLService) IsSubscribed(ctx context.Context, req *orlyaclv1.PubkeyRequest) (*orlyaclv1.BoolResponse, error) {
818 paid := s.getPaidACL()
819 if paid == nil {
820 return nil, status.Errorf(codes.FailedPrecondition, "paid ACL not available")
821 }
822 return &orlyaclv1.BoolResponse{Value: paid.IsSubscribed(req.Pubkey)}, nil
823 }
824
825 func (s *ACLService) GetSubscription(ctx context.Context, req *orlyaclv1.PubkeyRequest) (*orlyaclv1.SubscriptionResponse, error) {
826 paid := s.getPaidACL()
827 if paid == nil {
828 return nil, status.Errorf(codes.FailedPrecondition, "paid ACL not available")
829 }
830 sub, err := paid.GetSubscription(req.Pubkey)
831 if err != nil {
832 return nil, status.Errorf(codes.Internal, "failed to get subscription: %v", err)
833 }
834 resp := &orlyaclv1.SubscriptionResponse{
835 Pubkey: sub.PubkeyHex,
836 Alias: sub.Alias,
837 ExpiresAt: sub.ExpiresAt.Unix(),
838 CreatedAt: sub.CreatedAt.Unix(),
839 HasAlias: sub.Alias != "",
840 }
841 return resp, nil
842 }
843
844 func (s *ACLService) ClaimAlias(ctx context.Context, req *orlyaclv1.ClaimAliasRequest) (*orlyaclv1.Empty, error) {
845 paid := s.getPaidACL()
846 if paid == nil {
847 return nil, status.Errorf(codes.FailedPrecondition, "paid ACL not available")
848 }
849 if err := paid.ClaimAlias(req.Alias, req.Pubkey); err != nil {
850 if errors.Is(err, database.ErrAliasTaken) {
851 return nil, status.Errorf(codes.AlreadyExists, "alias is already taken")
852 }
853 return nil, status.Errorf(codes.Internal, "failed to claim alias: %v", err)
854 }
855 return &orlyaclv1.Empty{}, nil
856 }
857
858 func (s *ACLService) GetAliasByPubkey(ctx context.Context, req *orlyaclv1.PubkeyRequest) (*orlyaclv1.AliasResponse, error) {
859 paid := s.getPaidACL()
860 if paid == nil {
861 return nil, status.Errorf(codes.FailedPrecondition, "paid ACL not available")
862 }
863 alias, err := paid.GetAliasByPubkey(req.Pubkey)
864 if err != nil {
865 return nil, status.Errorf(codes.Internal, "failed to get alias: %v", err)
866 }
867 return &orlyaclv1.AliasResponse{Alias: alias}, nil
868 }
869
870 func (s *ACLService) GetPubkeyByAlias(ctx context.Context, req *orlyaclv1.AliasRequest) (*orlyaclv1.PubkeyResponse, error) {
871 paid := s.getPaidACL()
872 if paid == nil {
873 return nil, status.Errorf(codes.FailedPrecondition, "paid ACL not available")
874 }
875 pubkey, err := paid.GetPubkeyByAlias(req.Alias)
876 if err != nil {
877 return nil, status.Errorf(codes.Internal, "failed to get pubkey by alias: %v", err)
878 }
879 return &orlyaclv1.PubkeyResponse{Pubkey: pubkey}, nil
880 }
881
882 func (s *ACLService) IsAliasTaken(ctx context.Context, req *orlyaclv1.AliasRequest) (*orlyaclv1.BoolResponse, error) {
883 paid := s.getPaidACL()
884 if paid == nil {
885 return nil, status.Errorf(codes.FailedPrecondition, "paid ACL not available")
886 }
887 taken, err := paid.IsAliasTaken(req.Alias)
888 if err != nil {
889 return nil, status.Errorf(codes.Internal, "failed to check alias: %v", err)
890 }
891 return &orlyaclv1.BoolResponse{Value: taken}, nil
892 }
893
894 // === Helper Methods ===
895
896 func (s *ACLService) getPaidACL() *acl.Paid {
897 for _, i := range acl.Registry.ACLs() {
898 if i.Type() == "paid" {
899 if paid, ok := i.(*acl.Paid); ok {
900 return paid
901 }
902 }
903 }
904 return nil
905 }
906