blob: ef7c28153843ae5379000079df0e1487a87b1e16 [file] [log] [blame]
/**
* Copyright (c) 2024 Project CHIP Authors
*
* 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.
*/
#import "MTRDefines_Internal.h"
#import "MTRLogging_Internal.h"
#import <Matter/MTRAccessGrant.h>
#include <lib/core/CASEAuthTag.h>
#include <lib/core/GroupId.h>
#include <lib/core/NodeId.h>
#include <lib/support/SafeInt.h>
using namespace chip;
MTR_DIRECT_MEMBERS
@implementation MTRAccessGrant
+ (nullable MTRAccessGrant *)accessGrantForNodeID:(NSNumber *)nodeID privilege:(MTRAccessControlEntryPrivilege)privilege
{
NodeId id = nodeID.unsignedLongLongValue;
if (!IsOperationalNodeId(id)) {
MTR_LOG_ERROR("MTRAccessGrant provided non-operational node ID: 0x%llx", id);
return nil;
}
return [[MTRAccessGrant alloc] initWithSubject:[nodeID copy] privilege:privilege authenticationMode:MTRAccessControlEntryAuthModeCASE];
}
+ (nullable MTRAccessGrant *)accessGrantForCASEAuthenticatedTag:(NSNumber *)caseAuthenticatedTag privilege:(MTRAccessControlEntryPrivilege)privilege
{
auto value = caseAuthenticatedTag.unsignedLongLongValue;
if (!CanCastTo<CASEAuthTag>(value)) {
MTR_LOG_ERROR("MTRAccessGrant provided too-large CAT value: 0x%llx", value);
return nil;
}
CASEAuthTag tag = static_cast<CASEAuthTag>(value);
if (!IsValidCASEAuthTag(tag)) {
MTR_LOG_ERROR("MTRAccessGrant provided invalid CAT value: 0x%" PRIx32, tag);
return nil;
}
return [[MTRAccessGrant alloc] initWithSubject:@(NodeIdFromCASEAuthTag(tag)) privilege:privilege authenticationMode:MTRAccessControlEntryAuthModeCASE];
}
+ (nullable MTRAccessGrant *)accessGrantForGroupID:(NSNumber *)groupID privilege:(MTRAccessControlEntryPrivilege)privilege
{
auto value = groupID.unsignedLongLongValue;
if (!CanCastTo<GroupId>(value)) {
MTR_LOG_ERROR("MTRAccessGrant provided too-large group id: 0x%llx", value);
return nil;
}
GroupId id = static_cast<GroupId>(value);
if (!IsValidGroupId(id)) {
MTR_LOG_ERROR("MTRAccessGrant provided invalid group id: 0x%" PRIx32, id);
return nil;
}
return [[MTRAccessGrant alloc] initWithSubject:@(NodeIdFromGroupId(id)) privilege:privilege authenticationMode:MTRAccessControlEntryAuthModeGroup];
}
+ (MTRAccessGrant *)accessGrantForAllNodesWithPrivilege:(MTRAccessControlEntryPrivilege)privilege
{
return [[MTRAccessGrant alloc] initWithSubject:nil privilege:privilege authenticationMode:MTRAccessControlEntryAuthModeCASE];
}
// initWithSubject assumes that the subject has already been validated and, if
// needed, copied from the input.
- (nullable instancetype)initWithSubject:(nullable NSNumber *)subject privilege:(MTRAccessControlEntryPrivilege)privilege authenticationMode:(MTRAccessControlEntryAuthMode)authenticationMode
{
if (!(self = [super init])) {
return nil;
}
_subjectID = subject;
_grantedPrivilege = privilege;
_authenticationMode = authenticationMode;
return self;
}
- (id)copyWithZone:(NSZone *)zone
{
// We have no mutable state.
return self;
}
- (BOOL)isEqual:(id)object
{
if ([object class] != [self class]) {
return NO;
}
MTRAccessGrant * other = object;
BOOL sameSubjectID = (_subjectID == nil && other.subjectID == nil) || [_subjectID isEqual:other.subjectID];
return sameSubjectID && _grantedPrivilege == other.grantedPrivilege && _authenticationMode == other.authenticationMode;
}
- (NSUInteger)hash
{
return _subjectID.unsignedIntegerValue ^ _grantedPrivilege ^ _authenticationMode;
}
- (NSString *)description
{
NSString * privilege = @"Unknown";
switch (_grantedPrivilege) {
case MTRAccessControlEntryPrivilegeView:
privilege = @"View";
break;
case MTRAccessControlEntryPrivilegeProxyView:
privilege = @"ProxyView";
break;
case MTRAccessControlEntryPrivilegeOperate:
privilege = @"Operate";
break;
case MTRAccessControlEntryPrivilegeManage:
privilege = @"Manage";
break;
case MTRAccessControlEntryPrivilegeAdminister:
privilege = @"Administer";
break;
}
if (_subjectID == nil) {
return [NSString stringWithFormat:@"<%@ all nodes can %@>", self.class, privilege];
}
NodeId nodeId = static_cast<NodeId>(_subjectID.unsignedLongLongValue);
if (IsGroupId(nodeId)) {
return [NSString stringWithFormat:@"<%@ group 0x%x can %@>", self.class, GroupIdFromNodeId(nodeId), privilege];
}
if (IsCASEAuthTag(nodeId)) {
return [NSString stringWithFormat:@"<%@ nodes with CASE Authenticated Tag 0x%08x can %@>", self.class, CASEAuthTagFromNodeId(nodeId), privilege];
}
return [NSString stringWithFormat:@"<%@ node 0x%016llx can %@>", self.class, nodeId, privilege];
}
@end