<commit_before>// Copyright 2017 EDOMO Systems GmbH. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sessionrolemanager

import (
	"sort"

	"github.com/casbin/casbin/rbac"
	"github.com/casbin/casbin/util"
)

type RoleManager struct {
	allRoles          map[string]*SessionRole
	maxHierarchyLevel int
}

// SessionRoleManager provides an implementation for the RoleManagerConstructor that
// supports RBAC sessions with a start time and an end time.
func SessionRoleManager() rbac.RoleManagerConstructor {
	return func() rbac.RoleManager {
		return NewRoleManager(10)
	}
}

// NewRoleManager is the constructor for creating an instance of the
// SessionRoleManager implementation.
func NewRoleManager(maxHierarchyLevel int) rbac.RoleManager {
	rm := RoleManager{}
	rm.allRoles = make(map[string]*SessionRole)
	rm.maxHierarchyLevel = maxHierarchyLevel
	return &rm
}

func (rm *RoleManager) hasRole(name string) bool {
	_, ok := rm.allRoles[name]
	return ok
}

func (rm *RoleManager) createRole(name string) *SessionRole {
	if !rm.hasRole(name) {
		rm.allRoles[name] = newSessionRole(name)
	}
	return rm.allRoles[name]
}

// Clear clears all stored data and resets the role manager to the initial state.
func (rm *RoleManager) Clear() {
	rm.allRoles = make(map[string]*SessionRole)
}

func (rm *RoleManager) AddLink(name1 string, name2 string, timeRange ...string) {
	if len(timeRange) != 2 {
		return
	}
	startTime := timeRange[0]
	endTime := timeRange[1]

	role1 := rm.createRole(name1)
	role2 := rm.createRole(name2)

	session := Session{role2, startTime, endTime}
	role1.addSession(session)
}

func (rm *RoleManager) DeleteLink(name1 string, name2 string, unused ...string) {
	if !rm.hasRole(name1) || !rm.hasRole(name2) {
		return
	}

	role1 := rm.createRole(name1)
	role2 := rm.createRole(name2)

	role1.deleteSessions(role2.name)
}

func (rm *RoleManager) HasLink(name1 string, name2 string, requestTime ...string) bool {
	if len(requestTime) != 1 {
		return false
	}

	if name1 == name2 {
		return true
	}

	if !rm.hasRole(name1) || !rm.hasRole(name2) {
		return false
	}

	role1 := rm.createRole(name1)
	return role1.hasValidSession(name2, rm.maxHierarchyLevel, requestTime[0])
}

func (rm *RoleManager) GetRoles(name string, currentTime ...string) []string {
	if len(currentTime) != 1 {
		return nil
	}
	requestTime := currentTime[0]

	if !rm.hasRole(name) {
		return nil
	}

	sessionRoles := rm.createRole(name).getSessionRoles(requestTime)
	return sessionRoles
}

func (rm *RoleManager) GetUsers(name string, currentTime ...string) []string {
	if len(currentTime) != 1 {
		return nil
	}
	requestTime := currentTime[0]

	users := []string{}
	for _, role := range rm.allRoles {
		if role.hasDirectRole(name, requestTime) {
			users = append(users, role.name)
		}
	}
	sort.Strings(users)
	return users
}

func (rm *RoleManager) PrintRoles() {
	for _, role := range rm.allRoles {
		util.LogPrint(role.toString())
	}
}

// SessionRole is a modified version of the default role.
// A SessionRole not only has a name, but also a list of sessions.
type SessionRole struct {
	name     string
	sessions []Session
}<commit_msg>Add comments to the session role manager.<commit_after>// Copyright 2017 EDOMO Systems GmbH. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package sessionrolemanager

import (
	"sort"

	"github.com/casbin/casbin/rbac"
	"github.com/casbin/casbin/util"
)

type RoleManager struct {
	allRoles          map[string]*SessionRole
	maxHierarchyLevel int
}

// SessionRoleManager provides an implementation for the RoleManagerConstructor that
// supports RBAC sessions with a start time and an end time.
func SessionRoleManager() rbac.RoleManagerConstructor {
	return func() rbac.RoleManager {
		return NewRoleManager(10)
	}
}

// NewRoleManager is the constructor for creating an instance of the
// SessionRoleManager implementation.
func NewRoleManager(maxHierarchyLevel int) rbac.RoleManager {
	rm := RoleManager{}
	rm.allRoles = make(map[string]*SessionRole)
	rm.maxHierarchyLevel = maxHierarchyLevel
	return &rm
}

func (rm *RoleManager) hasRole(name string) bool {
	_, ok := rm.allRoles[name]
	return ok
}

func (rm *RoleManager) createRole(name string) *SessionRole {
	if !rm.hasRole(name) {
		rm.allRoles[name] = newSessionRole(name)
	}
	return rm.allRoles[name]
}

// Clear clears all stored data and resets the role manager to the initial state.
func (rm *RoleManager) Clear() {
	rm.allRoles = make(map[string]*SessionRole)
}

// AddLink adds the inheritance link between role: name1 and role: name2.
// aka role: name1 inherits role: name2.
// timeRange is the time range when the role inheritance link is active.
func (rm *RoleManager) AddLink(name1 string, name2 string, timeRange ...string) {
	if len(timeRange) != 2 {
		return
	}
	startTime := timeRange[0]
	endTime := timeRange[1]

	role1 := rm.createRole(name1)
	role2 := rm.createRole(name2)

	session := Session{role2, startTime, endTime}
	role1.addSession(session)
}

// DeleteLink deletes the inheritance link between role: name1 and role: name2.
// aka role: name1 does not inherit role: name2 any more.
// unused is not used.
func (rm *RoleManager) DeleteLink(name1 string, name2 string, unused ...string) {
	if !rm.hasRole(name1) || !rm.hasRole(name2) {
		return
	}

	role1 := rm.createRole(name1)
	role2 := rm.createRole(name2)

	role1.deleteSessions(role2.name)
}

// HasLink determines whether role: name1 inherits role: name2.
// requestTime is the querying time for the role inheritance link.
func (rm *RoleManager) HasLink(name1 string, name2 string, requestTime ...string) bool {
	if len(requestTime) != 1 {
		return false
	}

	if name1 == name2 {
		return true
	}

	if !rm.hasRole(name1) || !rm.hasRole(name2) {
		return false
	}

	role1 := rm.createRole(name1)
	return role1.hasValidSession(name2, rm.maxHierarchyLevel, requestTime[0])
}

// GetRoles gets the roles that a subject inherits.
// currentTime is the querying time for the role inheritance link.
func (rm *RoleManager) GetRoles(name string, currentTime ...string) []string {
	if len(currentTime) != 1 {
		return nil
	}
	requestTime := currentTime[0]

	if !rm.hasRole(name) {
		return nil
	}

	sessionRoles := rm.createRole(name).getSessionRoles(requestTime)
	return sessionRoles
}

// GetUsers gets the users that inherits a subject.
// currentTime is the querying time for the role inheritance link.
func (rm *RoleManager) GetUsers(name string, currentTime ...string) []string {
	if len(currentTime) != 1 {
		return nil
	}
	requestTime := currentTime[0]

	users := []string{}
	for _, role := range rm.allRoles {
		if role.hasDirectRole(name, requestTime) {
			users = append(users, role.name)
		}
	}
	sort.Strings(users)
	return users
}

// PrintRoles prints all the roles to log.
func (rm *RoleManager) PrintRoles() {
	for _, role := range rm.allRoles {
		util.LogPrint(role.toString())
	}
}

// SessionRole is a modified version of the default role.
// A SessionRole not only has a name, but also a list of sessions.
type SessionRole struct {
	name     string
	sessions []Session
}
{'fraction_non_alphanumeric': 0.10860731437015146, 'fraction_numerical': 0.012806304642285432, 'mean_word_length': 4.104965430546826, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5888276', 'n_tokens_mistral': 2667, 'n_tokens_neox': 2579, 'n_words': 839}