- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等) - java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等) - javax/ 4个模块 (net/crypto/security/sql) - org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http) - dalvik/ 1个模块 (system) - ~3053个类/接口,方法签名完全对齐Android SDK - 桌面跨平台运行 (Windows/macOS/Linux) - 修复所有导入错误和Python关键字冲突
768 lines
22 KiB
Python
768 lines
22 KiB
Python
"""
|
|
Java javax.security APIs implemented in Python.
|
|
javax.security package - Subject, Principal, Policy, Permission, etc.
|
|
Desktop stub implementation.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
from typing import List, Set, Optional
|
|
|
|
__all__ = [
|
|
"AuthProvider", "Subject", "Principal", "Policy",
|
|
"PrivateCredentialPermission", "SubjectDomainCombiner",
|
|
"Refreshable", "Destroyable",
|
|
"RefreshFailedException", "DestroyFailedException",
|
|
"CredentialException", "CredentialExpiredException",
|
|
"CredentialNotFoundException", "UnrecoverableKeyException",
|
|
"UnrecoverableEntryException", "KeyStoreCallbackHandler",
|
|
"DomainLoadStoreParameter",
|
|
"Certificate", "CodeSource", "ProtectionDomain",
|
|
"Permissions", "AllPermission", "BasicPermission",
|
|
"Permission", "PermissionCollection", "UnresolvedPermission",
|
|
"PermissionsEnumerator", "Guard", "GuardedObject",
|
|
]
|
|
|
|
|
|
# ============================================================
|
|
# Principal
|
|
# ============================================================
|
|
|
|
class Principal(Stub):
|
|
"""
|
|
java.security.Principal
|
|
Represents a principal (entity) such as a user or group.
|
|
"""
|
|
|
|
def __init__(self, name: str = ""):
|
|
super().__init__()
|
|
self._name = name
|
|
|
|
def getName(self) -> str:
|
|
return self._name
|
|
|
|
def implies(self, subject: "Subject") -> bool:
|
|
return False
|
|
|
|
def toString(self) -> str:
|
|
return self._name
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, Principal):
|
|
return self._name == other._name
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._name) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# Subject
|
|
# ============================================================
|
|
|
|
class Subject(Stub):
|
|
"""
|
|
javax.security.auth.Subject
|
|
Represents a grouping of related information for a single entity.
|
|
"""
|
|
|
|
def __init__(self, read_only: bool = False,
|
|
principals: Set[Principal] = None,
|
|
pub_creds: Set = None,
|
|
priv_creds: Set = None):
|
|
super().__init__()
|
|
self._read_only = read_only
|
|
self._principals = set(principals) if principals else set()
|
|
self._public_credentials = set(pub_creds) if pub_creds else set()
|
|
self._private_credentials = set(priv_creds) if priv_creds else set()
|
|
|
|
def getPrincipals(self) -> Set[Principal]:
|
|
return set(self._principals)
|
|
|
|
def getPrivateCredentials(self) -> Set:
|
|
return set(self._private_credentials)
|
|
|
|
def getPublicCredentials(self) -> Set:
|
|
return set(self._public_credentials)
|
|
|
|
def setReadOnly(self):
|
|
self._read_only = True
|
|
|
|
def isReadOnly(self) -> bool:
|
|
return self._read_only
|
|
|
|
@staticmethod
|
|
def doAs(subject: "Subject", action: callable) -> Any:
|
|
return action()
|
|
|
|
@staticmethod
|
|
def doAsPrivileged(subject: "Subject", action: callable, access: Any) -> Any:
|
|
return action()
|
|
|
|
def toString(self) -> str:
|
|
return (f"Subject@{hex(id(self))}[principals={len(self._principals)}, "
|
|
f"read_only={self._read_only}]")
|
|
|
|
def equals(self, other) -> bool:
|
|
if not isinstance(other, Subject):
|
|
return False
|
|
return (self._principals == other._principals and
|
|
self._read_only == other._read_only)
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(frozenset(self._principals)) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# Policy
|
|
# ============================================================
|
|
|
|
class Policy(Stub):
|
|
"""
|
|
java.security.Policy
|
|
Policy for permissions (stub).
|
|
"""
|
|
_policy = None
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._parameters = None
|
|
|
|
@staticmethod
|
|
def getPolicy() -> "Policy":
|
|
if Policy._policy is None:
|
|
Policy._policy = Policy()
|
|
return Policy._policy
|
|
|
|
@staticmethod
|
|
def setPolicy(policy: "Policy"):
|
|
Policy._policy = policy
|
|
|
|
def getParameters(self):
|
|
return self._parameters
|
|
|
|
def setParameters(self, params):
|
|
self._parameters = params
|
|
|
|
def implies(self, domain: "ProtectionDomain", permission: "Permission") -> bool:
|
|
return True
|
|
|
|
def toString(self) -> str:
|
|
return f"Policy@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# AuthProvider
|
|
# ============================================================
|
|
|
|
class AuthProvider(Stub):
|
|
"""
|
|
javax.security.auth.AuthProvider
|
|
Provider for authentication services.
|
|
"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def login(self, subject: Subject, handler: Any):
|
|
pass
|
|
|
|
def logout(self, subject: Subject):
|
|
pass
|
|
|
|
def setCallbackHandler(self, handler: Any):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"AuthProvider@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# PrivateCredentialPermission
|
|
# ============================================================
|
|
|
|
class PrivateCredentialPermission(Stub):
|
|
"""
|
|
javax.security.auth.PrivateCredentialPermission
|
|
Permission to access private credentials.
|
|
"""
|
|
def __init__(self, name: str = "", actions: str = "read"):
|
|
super().__init__()
|
|
self._name = name
|
|
self._actions = actions
|
|
|
|
def getName(self) -> str:
|
|
return self._name
|
|
|
|
def getActions(self) -> str:
|
|
return self._actions
|
|
|
|
def getCredentialClass(self) -> str:
|
|
return self._name
|
|
|
|
def getPrincipals(self) -> List[List]:
|
|
return []
|
|
|
|
def implies(self, permission: "Permission") -> bool:
|
|
return isinstance(permission, PrivateCredentialPermission) and self._name == permission._name
|
|
|
|
def toString(self) -> str:
|
|
return f'PrivateCredentialPermission "{self._name}" "{self._actions}"'
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, PrivateCredentialPermission):
|
|
return self._name == other._name and self._actions == other._actions
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash((self._name, self._actions)) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# SubjectDomainCombiner
|
|
# ============================================================
|
|
|
|
class SubjectDomainCombiner(Stub):
|
|
"""
|
|
javax.security.auth.SubjectDomainCombiner
|
|
Combines ProtectionDomains with Subject context.
|
|
"""
|
|
def __init__(self, subject: Subject):
|
|
super().__init__()
|
|
self._subject = subject
|
|
|
|
def combine(self, current_domains: List, assigned_domains: List) -> List:
|
|
return list(current_domains or []) + list(assigned_domains or [])
|
|
|
|
def getSubject(self) -> Subject:
|
|
return self._subject
|
|
|
|
def toString(self) -> str:
|
|
return f"SubjectDomainCombiner@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# Refreshable / Destroyable interfaces
|
|
# ============================================================
|
|
|
|
class Refreshable(Stub):
|
|
"""
|
|
javax.security.auth.Refreshable
|
|
Interface for refreshable credentials.
|
|
"""
|
|
def isCurrent(self) -> bool:
|
|
return True
|
|
|
|
def refresh(self):
|
|
raise AndroidOnlyError("refresh not supported on desktop")
|
|
|
|
|
|
class Destroyable(Stub):
|
|
"""
|
|
javax.security.auth.Destroyable
|
|
Interface for destroyable credentials.
|
|
"""
|
|
def isDestroyed(self) -> bool:
|
|
return False
|
|
|
|
def destroy(self):
|
|
pass
|
|
|
|
|
|
# ============================================================
|
|
# Exceptions
|
|
# ============================================================
|
|
|
|
class RefreshFailedException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Refresh failed")
|
|
self._message = message
|
|
def toString(self) -> str:
|
|
return f"RefreshFailedException: {self._message}"
|
|
def equals(self, other) -> bool:
|
|
return isinstance(other, RefreshFailedException) and self._message == other._message
|
|
def hashCode(self) -> int:
|
|
return hash(self._message) & 0x7FFFFFFF
|
|
|
|
|
|
class DestroyFailedException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Destroy failed")
|
|
self._message = message
|
|
def toString(self) -> str:
|
|
return f"DestroyFailedException: {self._message}"
|
|
def equals(self, other) -> bool:
|
|
return isinstance(other, DestroyFailedException) and self._message == other._message
|
|
def hashCode(self) -> int:
|
|
return hash(self._message) & 0x7FFFFFFF
|
|
|
|
|
|
class CredentialException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Credential error")
|
|
self._message = message
|
|
def toString(self) -> str:
|
|
return f"CredentialException: {self._message}"
|
|
|
|
|
|
class CredentialExpiredException(CredentialException):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Credential expired")
|
|
|
|
|
|
class CredentialNotFoundException(CredentialException):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Credential not found")
|
|
|
|
|
|
class UnrecoverableKeyException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Unrecoverable key")
|
|
self._message = message
|
|
def toString(self) -> str:
|
|
return f"UnrecoverableKeyException: {self._message}"
|
|
|
|
|
|
class UnrecoverableEntryException(Exception, Stub):
|
|
def __init__(self, message: str = None):
|
|
super().__init__(message or "Unrecoverable entry")
|
|
self._message = message
|
|
def toString(self) -> str:
|
|
return f"UnrecoverableEntryException: {self._message}"
|
|
|
|
|
|
# ============================================================
|
|
# KeyStoreCallbackHandler
|
|
# ============================================================
|
|
|
|
class KeyStoreCallbackHandler(Stub):
|
|
"""
|
|
javax.security.auth.callback.KeyStoreCallbackHandler
|
|
Handler for key store callbacks.
|
|
"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def handle(self, callbacks: List):
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"KeyStoreCallbackHandler@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# DomainLoadStoreParameter
|
|
# ============================================================
|
|
|
|
class DomainLoadStoreParameter(Stub):
|
|
"""
|
|
java.security.DomainLoadStoreParameter
|
|
Configuration data for loading/storing keystore domains.
|
|
"""
|
|
def __init__(self, config: dict = None):
|
|
super().__init__()
|
|
self._config = config or {}
|
|
|
|
def getConfiguration(self) -> dict:
|
|
return self._config
|
|
|
|
def toString(self) -> str:
|
|
return f"DomainLoadStoreParameter@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# Certificate
|
|
# ============================================================
|
|
|
|
class Certificate(Stub):
|
|
"""
|
|
java.security.cert.Certificate
|
|
Abstract class for managing certificates.
|
|
"""
|
|
def __init__(self, cert_type: str = "X.509", encoded: bytes = None):
|
|
super().__init__()
|
|
self._cert_type = cert_type
|
|
self._encoded = encoded or b''
|
|
|
|
def getType(self) -> str:
|
|
return self._cert_type
|
|
|
|
def getEncoded(self) -> bytes:
|
|
return self._encoded
|
|
|
|
def getPublicKey(self):
|
|
return None
|
|
|
|
def toString(self) -> str:
|
|
return f"Certificate@{hex(id(self))}[type={self._cert_type}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, Certificate):
|
|
return self._encoded == other._encoded
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(bytes(self._encoded)) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# Permission & PermissionCollection
|
|
# ============================================================
|
|
|
|
class Permission(Stub):
|
|
"""
|
|
java.security.Permission
|
|
Abstract class for representing access to a system resource.
|
|
"""
|
|
def __init__(self, name: str = ""):
|
|
super().__init__()
|
|
self._name = name
|
|
|
|
def getName(self) -> str:
|
|
return self._name
|
|
|
|
def getActions(self) -> str:
|
|
return ""
|
|
|
|
def implies(self, permission: "Permission") -> bool:
|
|
return self.equals(permission)
|
|
|
|
def toString(self) -> str:
|
|
return f'Permission "{self._name}"'
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, Permission):
|
|
return self._name == other._name
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._name) & 0x7FFFFFFF
|
|
|
|
|
|
class PermissionCollection(Stub):
|
|
"""
|
|
java.security.PermissionCollection
|
|
Abstract class for holding a collection of Permission objects.
|
|
"""
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._permissions = []
|
|
self._read_only = False
|
|
|
|
def add(self, permission: Permission):
|
|
if not self._read_only:
|
|
self._permissions.append(permission)
|
|
|
|
def implies(self, permission: Permission) -> bool:
|
|
for p in self._permissions:
|
|
if p.implies(permission):
|
|
return True
|
|
return False
|
|
|
|
def elements(self):
|
|
return iter(self._permissions)
|
|
|
|
def isReadOnly(self) -> bool:
|
|
return self._read_only
|
|
|
|
def setReadOnly(self):
|
|
self._read_only = True
|
|
|
|
def toString(self) -> str:
|
|
return f"PermissionCollection@{hex(id(self))}[size={len(self._permissions)}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
class Permissions(PermissionCollection):
|
|
"""
|
|
java.security.Permissions
|
|
A collection of Permission objects.
|
|
"""
|
|
def add(self, permission: Permission):
|
|
super().add(permission)
|
|
|
|
def implies(self, permission: Permission) -> bool:
|
|
return super().implies(permission)
|
|
|
|
def elements(self):
|
|
return super().elements()
|
|
|
|
def toString(self) -> str:
|
|
return f"Permissions@{hex(id(self))}[size={len(self._permissions)}]"
|
|
|
|
|
|
class AllPermission(Permission):
|
|
"""
|
|
java.security.AllPermission
|
|
A permission that implies all other permissions.
|
|
"""
|
|
def __init__(self):
|
|
super().__init__("<all permissions>")
|
|
|
|
def implies(self, permission: Permission) -> bool:
|
|
return True
|
|
|
|
def getActions(self) -> str:
|
|
return "<all actions>"
|
|
|
|
def toString(self) -> str:
|
|
return "AllPermission"
|
|
|
|
|
|
class BasicPermission(Permission):
|
|
"""
|
|
java.security.BasicPermission
|
|
Base class for basic permissions.
|
|
"""
|
|
def __init__(self, name: str = "", actions: str = ""):
|
|
super().__init__(name)
|
|
self._actions = actions
|
|
|
|
def implies(self, permission: Permission) -> bool:
|
|
if isinstance(permission, BasicPermission):
|
|
return self._name == permission._name or permission._name.startswith(self._name + ".")
|
|
return False
|
|
|
|
def getActions(self) -> str:
|
|
return self._actions
|
|
|
|
def toString(self) -> str:
|
|
return f'BasicPermission "{self._name}"'
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, BasicPermission):
|
|
return self._name == other._name
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._name) & 0x7FFFFFFF
|
|
|
|
|
|
class UnresolvedPermission(Permission):
|
|
"""
|
|
java.security.UnresolvedPermission
|
|
A permission that was not resolved when the PermissionCollection was built.
|
|
"""
|
|
def __init__(self, perm_type: str = "", name: str = "", actions: str = "",
|
|
certs: List = None):
|
|
super().__init__(name)
|
|
self._unresolved_type = perm_type
|
|
self._unresolved_actions = actions
|
|
self._unresolved_certs = certs or []
|
|
|
|
def getUnresolvedType(self) -> str:
|
|
return self._unresolved_type
|
|
|
|
def getUnresolvedName(self) -> str:
|
|
return self._name
|
|
|
|
def getUnresolvedActions(self) -> str:
|
|
return self._unresolved_actions
|
|
|
|
def getUnresolvedCerts(self) -> List:
|
|
return list(self._unresolved_certs)
|
|
|
|
def implies(self, permission: Permission) -> bool:
|
|
return False
|
|
|
|
def toString(self) -> str:
|
|
return f'UnresolvedPermission "{self._unresolved_type}" "{self._name}" "{self._unresolved_actions}"'
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, UnresolvedPermission):
|
|
return (self._unresolved_type == other._unresolved_type and
|
|
self._name == other._name)
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash((self._unresolved_type, self._name)) & 0x7FFFFFFF
|
|
|
|
|
|
class PermissionsEnumerator(Stub):
|
|
"""
|
|
java.security.PermissionsEnumerator
|
|
Enumerator over Permission objects.
|
|
"""
|
|
def __init__(self, permissions: List):
|
|
super().__init__()
|
|
self._permissions = list(permissions)
|
|
self._index = 0
|
|
|
|
def hasMoreElements(self) -> bool:
|
|
return self._index < len(self._permissions)
|
|
|
|
def nextElement(self) -> Permission:
|
|
if self._index < len(self._permissions):
|
|
p = self._permissions[self._index]
|
|
self._index += 1
|
|
return p
|
|
return None
|
|
|
|
def toString(self) -> str:
|
|
return f"PermissionsEnumerator@{hex(id(self))}"
|
|
|
|
|
|
# ============================================================
|
|
# CodeSource
|
|
# ============================================================
|
|
|
|
class CodeSource(Stub):
|
|
"""
|
|
java.security.CodeSource
|
|
Represents the codebase and certificates from which code originated.
|
|
"""
|
|
def __init__(self, location: str = None, certs: List = None,
|
|
code_signers: List = None):
|
|
super().__init__()
|
|
self._location = location
|
|
self._certificates = certs or []
|
|
self._code_signers = code_signers or []
|
|
|
|
def getCertificates(self) -> List:
|
|
return list(self._certificates)
|
|
|
|
def getCodeSigners(self) -> List:
|
|
return list(self._code_signers)
|
|
|
|
def getLocation(self) -> str:
|
|
return self._location
|
|
|
|
def implies(self, codesource: "CodeSource") -> bool:
|
|
return self._location == codesource._location
|
|
|
|
def toString(self) -> str:
|
|
return f"CodeSource@{hex(id(self))}[location={self._location}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
if isinstance(other, CodeSource):
|
|
return self._location == other._location
|
|
return False
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self._location) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# ProtectionDomain
|
|
# ============================================================
|
|
|
|
class ProtectionDomain(Stub):
|
|
"""
|
|
java.security.ProtectionDomain
|
|
Groups a CodeSource and Permissions for code access control.
|
|
"""
|
|
def __init__(self, codesource: CodeSource = None,
|
|
permissions: PermissionCollection = None,
|
|
principals: List[Principal] = None,
|
|
static_permissions: bool = False):
|
|
super().__init__()
|
|
self._codesource = codesource
|
|
self._permissions = permissions or Permissions()
|
|
self._principals = principals or []
|
|
self._static_permissions = static_permissions
|
|
|
|
def getCodeSource(self) -> CodeSource:
|
|
return self._codesource
|
|
|
|
def getPermissions(self) -> PermissionCollection:
|
|
return self._permissions
|
|
|
|
def getPrincipals(self) -> List[Principal]:
|
|
return list(self._principals)
|
|
|
|
def implies(self, permission: Permission) -> bool:
|
|
return self._permissions.implies(permission) if self._permissions else False
|
|
|
|
def toString(self) -> str:
|
|
return f"ProtectionDomain@{hex(id(self))}[codesource={self._codesource}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ============================================================
|
|
# Guard & GuardedObject
|
|
# ============================================================
|
|
|
|
class Guard(Stub):
|
|
"""
|
|
java.security.Guard
|
|
Interface for objects that guard access to another object.
|
|
"""
|
|
def checkGuard(self, obj: Any):
|
|
raise NotImplementedError
|
|
|
|
def toString(self) -> str:
|
|
return f"Guard@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF
|
|
|
|
|
|
class GuardedObject(Stub):
|
|
"""
|
|
java.security.GuardedObject
|
|
Wraps an object and guards access to it with a Guard.
|
|
"""
|
|
def __init__(self, obj: Any = None, guard: Guard = None):
|
|
super().__init__()
|
|
self._object = obj
|
|
self._guard = guard
|
|
|
|
def getObject(self) -> Any:
|
|
if self._guard:
|
|
self._guard.checkGuard(self._object)
|
|
return self._object
|
|
|
|
def setGuard(self, guard: Guard):
|
|
self._guard = guard
|
|
|
|
def toString(self) -> str:
|
|
return f"GuardedObject@{hex(id(self))}[guarded={self._guard is not None}]"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return hash(self) & 0x7FFFFFFF |