1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-04-29 13:49:28 +08:00
Mirko Teodorovic fbba7aaa1a
MF-1248 - Add access policies for users (#1246)
* authz service init

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* authz service init

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add proto

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add proto

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* authorize method

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add casbib

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add casbib

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add casbib

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add policy grpc

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add policy grpc

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix db connection, add environment variables, docker-compose

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add model.conf policy

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* add model.conf policy

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix test

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* adding tests, and token for auth

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* revert changes

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix auth service

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* small changes, add model conf env var

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* remove users grpc for now

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix error

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* some cosmetics

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* resolvin minor comments

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* change endpoint, add file to fix test

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix docker env

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>

* fix alignment and path for model.conf

Signed-off-by: Mirko Teodorovic <mirko.teodorovic@gmail.com>
2020-12-08 17:04:09 +01:00

340 lines
6.4 KiB
Go

// Package kace provides common case conversion functions which take into
// consideration common initialisms.
package kace
import (
"fmt"
"strings"
"unicode"
"github.com/codemodus/kace/ktrie"
)
const (
kebabDelim = '-'
snakeDelim = '_'
none = rune(-1)
)
var (
ciTrie *ktrie.KTrie
)
func init() {
var err error
if ciTrie, err = ktrie.NewKTrie(ciMap); err != nil {
panic(err)
}
}
// Camel returns a camelCased string.
func Camel(s string) string {
return camelCase(ciTrie, s, false)
}
// Pascal returns a PascalCased string.
func Pascal(s string) string {
return camelCase(ciTrie, s, true)
}
// Kebab returns a kebab-cased string with all lowercase letters.
func Kebab(s string) string {
return delimitedCase(s, kebabDelim, false)
}
// KebabUpper returns a KEBAB-CASED string with all upper case letters.
func KebabUpper(s string) string {
return delimitedCase(s, kebabDelim, true)
}
// Snake returns a snake_cased string with all lowercase letters.
func Snake(s string) string {
return delimitedCase(s, snakeDelim, false)
}
// SnakeUpper returns a SNAKE_CASED string with all upper case letters.
func SnakeUpper(s string) string {
return delimitedCase(s, snakeDelim, true)
}
// Kace provides common case conversion methods which take into
// consideration common initialisms set by the user.
type Kace struct {
t *ktrie.KTrie
}
// New returns a pointer to an instance of kace loaded with a common
// initialsms trie based on the provided map. Before conversion to a
// trie, the provided map keys are all upper cased.
func New(initialisms map[string]bool) (*Kace, error) {
ci := initialisms
if ci == nil {
ci = map[string]bool{}
}
ci = sanitizeCI(ci)
t, err := ktrie.NewKTrie(ci)
if err != nil {
return nil, fmt.Errorf("kace: cannot create trie: %s", err)
}
k := &Kace{
t: t,
}
return k, nil
}
// Camel returns a camelCased string.
func (k *Kace) Camel(s string) string {
return camelCase(k.t, s, false)
}
// Pascal returns a PascalCased string.
func (k *Kace) Pascal(s string) string {
return camelCase(k.t, s, true)
}
// Snake returns a snake_cased string with all lowercase letters.
func (k *Kace) Snake(s string) string {
return delimitedCase(s, snakeDelim, false)
}
// SnakeUpper returns a SNAKE_CASED string with all upper case letters.
func (k *Kace) SnakeUpper(s string) string {
return delimitedCase(s, snakeDelim, true)
}
// Kebab returns a kebab-cased string with all lowercase letters.
func (k *Kace) Kebab(s string) string {
return delimitedCase(s, kebabDelim, false)
}
// KebabUpper returns a KEBAB-CASED string with all upper case letters.
func (k *Kace) KebabUpper(s string) string {
return delimitedCase(s, kebabDelim, true)
}
func camelCase(t *ktrie.KTrie, s string, ucFirst bool) string {
rs := []rune(s)
offset := 0
prev := none
for i := 0; i < len(rs); i++ {
r := rs[i]
switch {
case unicode.IsLetter(r):
ucCurr := isToBeUpper(r, prev, ucFirst)
if ucCurr || isSegmentStart(r, prev) {
prv, skip := updateRunes(rs, i, offset, t, ucCurr)
if skip > 0 {
i += skip - 1
prev = prv
continue
}
}
prev = updateRune(rs, i, offset, ucCurr)
continue
case unicode.IsNumber(r):
prev = updateRune(rs, i, offset, false)
continue
default:
prev = r
offset--
}
}
return string(rs[:len(rs)+offset])
}
func isToBeUpper(curr, prev rune, ucFirst bool) bool {
if prev == none {
return ucFirst
}
return isSegmentStart(curr, prev)
}
func isSegmentStart(curr, prev rune) bool {
if !unicode.IsLetter(prev) || unicode.IsUpper(curr) && unicode.IsLower(prev) {
return true
}
return false
}
func updateRune(rs []rune, i, offset int, upper bool) rune {
r := rs[i]
dest := i + offset
if dest < 0 || i > len(rs)-1 {
panic("this function has been used or designed incorrectly")
}
fn := unicode.ToLower
if upper {
fn = unicode.ToUpper
}
rs[dest] = fn(r)
return r
}
func updateRunes(rs []rune, i, offset int, t *ktrie.KTrie, upper bool) (rune, int) {
r := rs[i]
ns := nextSegment(rs, i)
ct := len(ns)
if ct < t.MinDepth() || ct > t.MaxDepth() || !t.FindAsUpper(ns) {
return r, 0
}
for j := i; j < i+ct; j++ {
r = updateRune(rs, j, offset, upper)
}
return r, ct
}
func nextSegment(rs []rune, i int) []rune {
for j := i; j < len(rs); j++ {
if !unicode.IsLetter(rs[j]) && !unicode.IsNumber(rs[j]) {
return rs[i:j]
}
if j == len(rs)-1 {
return rs[i : j+1]
}
}
return nil
}
func delimitedCase(s string, delim rune, upper bool) string {
buf := make([]rune, 0, len(s)*2)
for i := len(s); i > 0; i-- {
switch {
case unicode.IsLetter(rune(s[i-1])):
if i < len(s) && unicode.IsUpper(rune(s[i])) {
if i > 1 && unicode.IsLower(rune(s[i-1])) || i < len(s)-2 && unicode.IsLower(rune(s[i+1])) {
buf = append(buf, delim)
}
}
buf = appendCased(buf, upper, rune(s[i-1]))
case unicode.IsNumber(rune(s[i-1])):
if i == len(s) || i == 1 || unicode.IsNumber(rune(s[i])) {
buf = append(buf, rune(s[i-1]))
continue
}
buf = append(buf, delim, rune(s[i-1]))
default:
if i == len(s) {
continue
}
buf = append(buf, delim)
}
}
reverse(buf)
return string(buf)
}
func appendCased(rs []rune, upper bool, r rune) []rune {
if upper {
rs = append(rs, unicode.ToUpper(r))
return rs
}
rs = append(rs, unicode.ToLower(r))
return rs
}
func reverse(s []rune) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
var (
// github.com/golang/lint/blob/master/lint.go
ciMap = map[string]bool{
"ACL": true,
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTP": true,
"HTTPS": true,
"ID": true,
"IP": true,
"JSON": true,
"LHS": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SQL": true,
"SSH": true,
"TCP": true,
"TLS": true,
"TTL": true,
"UDP": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XMPP": true,
"XSRF": true,
"XSS": true,
}
)
func sanitizeCI(m map[string]bool) map[string]bool {
r := map[string]bool{}
for k := range m {
fn := func(r rune) rune {
if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
return -1
}
return r
}
k = strings.Map(fn, k)
k = strings.ToUpper(k)
if k == "" {
continue
}
r[k] = true
}
return r
}