blob: c8821997a539b118a2af02ba8f707744f821d69e [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package internal
import (
"encoding/json"
"reflect"
"v.io/v23/context"
"v.io/v23/security"
"v.io/v23/security/access"
"v.io/x/ref/lib/stats/counter"
"messenger/ifc"
)
func RateAclFromJSON(b []byte) (acl RateAcl, err error) {
if err = json.Unmarshal([]byte(b), &acl); err == nil {
acl.Init()
}
return
}
type RateAcl []struct {
Acl access.AccessList `json:"acl"`
Limit float32 `json:"limit"`
c *counter.Counter
}
func (r RateAcl) Init() {
for i := range r {
r[i].c = counter.New()
}
}
func (r RateAcl) Authorize(ctx *context.T, call security.Call) error {
if l, r := call.LocalBlessings().PublicKey(), call.RemoteBlessings().PublicKey(); l != nil && r != nil && reflect.DeepEqual(l, r) {
return nil
}
blessings, invalid := security.RemoteBlessingNames(ctx, call)
for i := range r {
if !r[i].Acl.Includes(blessings...) {
continue
}
if r[i].Limit == 0 {
ctx.Infof("No permissions for %v matched by %v", r[i].Acl, blessings)
break
}
if rate := r[i].c.Rate1m(); rate >= float64(r[i].Limit) {
ctx.Infof("Rate limit exceeded for %v matched by %v, %f >= %f", r[i].Acl, blessings, rate, r[i].Limit)
return ifc.NewErrRateLimitExceeded(ctx, r[i].Limit)
}
r[i].c.Incr(1)
return nil
}
return access.NewErrNoPermissions(ctx, blessings, invalid, "")
}