mirror of
https://github.com/GAM-team/GAM.git
synced 2026-07-04 21:01:36 +00:00
Phase 2 (partial): Move constants and calendar ACL helpers
This commit is contained in:
@@ -93,12 +93,55 @@ from gam.util.errors import (
|
||||
unknownArgumentExit,
|
||||
)
|
||||
from gam.util.fileio import UNKNOWN
|
||||
from gam.util.output import executeBatch, setSysExitRC
|
||||
from gam.util.output import executeBatch, formatKeyValueList, setSysExitRC
|
||||
from gam.constants import DAYS_OF_WEEK, GOOGLE_MEETID_FORMAT_REQUIRED, GOOGLE_MEETID_PATTERN, NO_ENTITIES_FOUND_RC
|
||||
|
||||
Act = glaction.GamAction()
|
||||
Ent = glentity.GamEntity()
|
||||
Ind = glindent.GamIndent()
|
||||
|
||||
|
||||
# ACL utility functions (moved from gam/__init__.py)
|
||||
def ACLRuleDict(rule):
|
||||
if rule['scope']['type'] != 'default':
|
||||
return {'Scope': f'{rule["scope"]["type"]}:{rule["scope"]["value"]}', 'Role': rule['role']}
|
||||
return {'Scope': f'{rule["scope"]["type"]}', 'Role': rule['role']}
|
||||
|
||||
def ACLRuleKeyValueList(rule):
|
||||
if rule['scope']['type'] != 'default':
|
||||
return ['Scope', f'{rule["scope"]["type"]}:{rule["scope"]["value"]}', 'Role', rule['role']]
|
||||
return ['Scope', f'{rule["scope"]["type"]}', 'Role', rule['role']}
|
||||
|
||||
def formatACLRule(rule):
|
||||
return formatKeyValueList('(', ACLRuleKeyValueList(rule), ')')
|
||||
|
||||
def formatACLScopeRole(scope, role):
|
||||
if role:
|
||||
return formatKeyValueList('(', ['Scope', scope, 'Role', role], ')')
|
||||
return formatKeyValueList('(', ['Scope', scope], ')')
|
||||
|
||||
def normalizeRuleId(ruleId):
|
||||
ruleIdParts = ruleId.split(':', 1)
|
||||
if (len(ruleIdParts) == 1) or not ruleIdParts[1]:
|
||||
if ruleIdParts[0] == 'default':
|
||||
return ruleId
|
||||
if ruleIdParts[0] == 'domain':
|
||||
return f'domain:{GC.Values[GC.DOMAIN]}'
|
||||
return f'user:{normalizeEmailAddressOrUID(ruleIdParts[0], noUid=True)}'
|
||||
if ruleIdParts[0] in {'user', 'group'}:
|
||||
return f'{ruleIdParts[0]}:{normalizeEmailAddressOrUID(ruleIdParts[1], noUid=True)}'
|
||||
return ruleId
|
||||
|
||||
def makeRoleRuleIdBody(role, ruleId):
|
||||
ruleIdParts = ruleId.split(':', 1)
|
||||
if len(ruleIdParts) == 1:
|
||||
if ruleIdParts[0] == 'default':
|
||||
return {'role': role, 'scope': {'type': ruleIdParts[0]}}
|
||||
if ruleIdParts[0] == 'domain':
|
||||
return {'role': role, 'scope': {'type': ruleIdParts[0], 'value': GC.Values[GC.DOMAIN]}}
|
||||
return {'role': role, 'scope': {'type': 'user', 'value': ruleIdParts[0]}}
|
||||
return {'role': role, 'scope': {'type': ruleIdParts[0], 'value': ruleIdParts[1]}}
|
||||
|
||||
Cmd = glclargs.GamCLArgs()
|
||||
|
||||
|
||||
@@ -234,7 +277,6 @@ def _normalizeCalIdGetRuleIds(origUser, user, origCal, calId, j, jcount, ACLScop
|
||||
return (calId, cal, ruleIds, kcount)
|
||||
|
||||
def _processCalendarACLs(cal, function, entityType, calId, j, jcount, k, kcount, role, ruleId, sendNotifications):
|
||||
from gam import formatACLScopeRole, makeRoleRuleIdBody
|
||||
result = True
|
||||
if function == 'insert':
|
||||
kwargs = {'body': makeRoleRuleIdBody(role, ruleId), 'fields': '', 'sendNotifications': sendNotifications}
|
||||
@@ -264,7 +306,6 @@ def _processCalendarACLs(cal, function, entityType, calId, j, jcount, k, kcount,
|
||||
return result
|
||||
|
||||
def _createCalendarACLs(cal, entityType, calId, j, jcount, role, ruleIds, kcount, sendNotifications):
|
||||
from gam import normalizeRuleId
|
||||
Ind.Increment()
|
||||
k = 0
|
||||
for ruleId in ruleIds:
|
||||
@@ -294,7 +335,6 @@ def doCalendarsCreateACLs(calIds):
|
||||
_doCalendarsCreateACLs(None, None, None, calIds, len(calIds), role, ACLScopeEntity, sendNotifications)
|
||||
|
||||
def _updateDeleteCalendarACLs(cal, function, entityType, calId, j, jcount, role, ruleIds, kcount, sendNotifications):
|
||||
from gam import normalizeRuleId
|
||||
Ind.Increment()
|
||||
k = 0
|
||||
for ruleId in ruleIds:
|
||||
@@ -334,7 +374,6 @@ def doCalendarsDeleteACLs(calIds):
|
||||
_doUpdateDeleteCalendarACLs(None, None, None, 'delete', calIds, len(calIds), ACLScopeEntity, role, False)
|
||||
|
||||
def _showCalendarACL(user, entityType, calId, acl, k, kcount, FJQC):
|
||||
from gam import ACLRuleKeyValueList
|
||||
if FJQC.formatJSON:
|
||||
if entityType == Ent.CALENDAR:
|
||||
if user:
|
||||
@@ -350,7 +389,6 @@ def _showCalendarACL(user, entityType, calId, acl, k, kcount, FJQC):
|
||||
printKeyValueListWithCount(ACLRuleKeyValueList(acl), k, kcount)
|
||||
|
||||
def _infoCalendarACLs(cal, user, entityType, calId, j, jcount, ruleIds, kcount, FJQC):
|
||||
from gam import formatACLScopeRole, normalizeRuleId
|
||||
Ind.Increment()
|
||||
k = 0
|
||||
for ruleId in ruleIds:
|
||||
|
||||
@@ -673,7 +673,7 @@ RESOURCE_FIELDS_WITH_CRS_NLS = {'resourceDescription'}
|
||||
|
||||
def _showResource(cd, resource, i, count, FJQC, acls=None, noSelfOwner=False):
|
||||
|
||||
from gam import ACLRuleKeyValueList
|
||||
from gam.cmd.calendar import ACLRuleKeyValueList
|
||||
def _showResourceField(title, resource, field):
|
||||
if field in resource:
|
||||
if field not in RESOURCE_FIELDS_WITH_CRS_NLS:
|
||||
|
||||
@@ -610,7 +610,7 @@ def _getCalendarAttributes(body, returnOnUnknownArgument=False):
|
||||
unknownArgumentExit()
|
||||
|
||||
def _showCalendar(calendar, j, jcount, FJQC, acls=None):
|
||||
from gam import ACLRuleKeyValueList
|
||||
from gam.cmd.calendar import ACLRuleKeyValueList
|
||||
if FJQC.formatJSON:
|
||||
if acls:
|
||||
calendar['acls'] = [{'id': rule['id'], 'role': rule['role']} for rule in acls]
|
||||
|
||||
@@ -146,6 +146,129 @@ YUBIKEY_VALUE_ERROR_RC = 85
|
||||
YUBIKEY_MULTIPLE_CONNECTED_RC = 86
|
||||
YUBIKEY_NOT_FOUND_RC = 87
|
||||
|
||||
|
||||
# Boolean constants
|
||||
TRUE = 'true'
|
||||
FALSE = 'false'
|
||||
TRUE_VALUES = [TRUE, 'on', 'yes', 'enabled', '1']
|
||||
FALSE_VALUES = [FALSE, 'off', 'no', 'disabled', '0']
|
||||
TRUE_FALSE = [TRUE, FALSE]
|
||||
|
||||
# Error/warning prefixes
|
||||
ERROR = 'ERROR'
|
||||
ERROR_PREFIX = ERROR + ': '
|
||||
WARNING = 'WARNING'
|
||||
WARNING_PREFIX = WARNING + ': '
|
||||
|
||||
# Byte sizes (powers of 10)
|
||||
ONE_KILO_10_BYTES = 1000
|
||||
ONE_MEGA_10_BYTES = ONE_KILO_10_BYTES * ONE_KILO_10_BYTES
|
||||
ONE_GIGA_10_BYTES = ONE_KILO_10_BYTES * ONE_MEGA_10_BYTES
|
||||
ONE_TERA_10_BYTES = ONE_KILO_10_BYTES * ONE_GIGA_10_BYTES
|
||||
|
||||
# Time durations in seconds
|
||||
SECONDS_PER_MINUTE = 60
|
||||
SECONDS_PER_HOUR = 3600
|
||||
SECONDS_PER_DAY = 86400
|
||||
SECONDS_PER_WEEK = 604800
|
||||
|
||||
# Google limits
|
||||
MAX_GOOGLE_SHEET_CELLS = 10000000 # See https://support.google.com/drive/answer/37603
|
||||
SHARED_DRIVE_MAX_FILES_FOLDERS = 500000
|
||||
|
||||
# Encoding
|
||||
UTF8 = 'utf-8'
|
||||
UTF8_SIG = 'utf-8-sig'
|
||||
|
||||
# Environment variable names
|
||||
EV_GAMCFGDIR = 'GAMCFGDIR'
|
||||
EV_GAMCFGSECTION = 'GAMCFGSECTION'
|
||||
EV_OLDGAMPATH = 'OLDGAMPATH'
|
||||
|
||||
# Config file names
|
||||
FN_GAM_CFG = 'gam.cfg'
|
||||
FN_LAST_UPDATE_CHECK_TXT = 'lastupdatecheck.txt'
|
||||
FN_GAMCOMMANDS_TXT = 'GamCommands.txt'
|
||||
|
||||
# Drive path constants
|
||||
ROOTID = 'rootid'
|
||||
ORPHANS = 'Orphans'
|
||||
SHARED_WITHME = 'SharedWithMe'
|
||||
SHARED_DRIVES = 'SharedDrives'
|
||||
|
||||
# Additional character sets
|
||||
URL_SAFE_CHARS = ALPHANUMERIC_CHARS + '-._~'
|
||||
FILENAME_SAFE_CHARS = ALPHANUMERIC_CHARS + "-_.() "
|
||||
CHAT_MESSAGEID_CHARS = string.ascii_lowercase + string.digits + '-'
|
||||
|
||||
# File mode constants
|
||||
DEFAULT_CSV_READ_MODE = 'r'
|
||||
DEFAULT_FILE_APPEND_MODE = 'a'
|
||||
DEFAULT_FILE_READ_MODE = 'r'
|
||||
DEFAULT_FILE_WRITE_MODE = 'w'
|
||||
|
||||
# Application URLs
|
||||
GAM_URL = f'https://github.com/{GIT_USER}/{GAM}'
|
||||
GAM_RELEASES = f'https://github.com/{GIT_USER}/{GAM}/releases'
|
||||
GAM_WIKI = f'https://github.com/{GIT_USER}/{GAM}/wiki'
|
||||
GAM_LATEST_RELEASE = f'https://api.github.com/repos/{GIT_USER}/{GAM}/releases/latest'
|
||||
|
||||
# Additional Google API MIME types
|
||||
MIMETYPE_GA_DOCUMENT = f'{APPLICATION_VND_GOOGLE_APPS}document'
|
||||
MIMETYPE_GA_DRAWING = f'{APPLICATION_VND_GOOGLE_APPS}drawing'
|
||||
MIMETYPE_GA_FILE = f'{APPLICATION_VND_GOOGLE_APPS}file'
|
||||
MIMETYPE_GA_FORM = f'{APPLICATION_VND_GOOGLE_APPS}form'
|
||||
MIMETYPE_GA_FUSIONTABLE = f'{APPLICATION_VND_GOOGLE_APPS}fusiontable'
|
||||
MIMETYPE_GA_JAM = f'{APPLICATION_VND_GOOGLE_APPS}jam'
|
||||
MIMETYPE_GA_MAP = f'{APPLICATION_VND_GOOGLE_APPS}map'
|
||||
MIMETYPE_GA_PRESENTATION = f'{APPLICATION_VND_GOOGLE_APPS}presentation'
|
||||
MIMETYPE_GA_SCRIPT = f'{APPLICATION_VND_GOOGLE_APPS}script'
|
||||
MIMETYPE_GA_SCRIPT_JSON = f'{APPLICATION_VND_GOOGLE_APPS}script+json'
|
||||
MIMETYPE_GA_3P_SHORTCUT = f'{APPLICATION_VND_GOOGLE_APPS}drive-sdk'
|
||||
MIMETYPE_GA_SITE = f'{APPLICATION_VND_GOOGLE_APPS}site'
|
||||
MIMETYPE_GA_SPREADSHEET = f'{APPLICATION_VND_GOOGLE_APPS}spreadsheet'
|
||||
MIMETYPE_TEXT_CSV = 'text/csv'
|
||||
MIMETYPE_TEXT_HTML = 'text/html'
|
||||
MIMETYPE_TEXT_PLAIN = 'text/plain'
|
||||
|
||||
# Google infrastructure
|
||||
GOOGLE_NAMESERVERS = ['8.8.8.8', '8.8.4.4']
|
||||
|
||||
# Date/time sentinel values
|
||||
NEVER_DATE = '1970-01-01'
|
||||
NEVER_DATETIME = '1970-01-01 00:00'
|
||||
NEVER_TIME = '1970-01-01T00:00:00.000Z'
|
||||
NEVER_TIME_NOMS = '1970-01-01T00:00:00Z'
|
||||
NEVER_END_DATE = '1969-12-31'
|
||||
NEVER_START_DATE = NEVER_DATE
|
||||
REFRESH_EXPIRY = '1970-01-01T00:00:01Z'
|
||||
UNKNOWN = 'Unknown'
|
||||
REPLACE_GROUP_PATTERN = re.compile(r'\\(\d+)')
|
||||
|
||||
# Additional Drive query fragments
|
||||
MY_FOLDERS = ME_IN_OWNERS_AND + ANY_FOLDERS
|
||||
WITH_ANY_FILE_NAME = "name = '{0}'"
|
||||
WITH_MY_FILE_NAME = ME_IN_OWNERS_AND + WITH_ANY_FILE_NAME
|
||||
WITH_OTHER_FILE_NAME = NOT_ME_IN_OWNERS_AND + WITH_ANY_FILE_NAME
|
||||
|
||||
# Debug redaction patterns
|
||||
DEBUG_REDACTION_PATTERNS = [
|
||||
# Positional patterns that redact sensitive credentials based on their location
|
||||
(r'(Bearer\s+)\S+', r'\1*****'), # access tokens and JWTs in auth header
|
||||
(r'([?&]refresh_token=)[^&]*', r'\1*****'), # refresh token URL parameter
|
||||
(r'([?&]client_secret=)[^&]*', r'\1*****'), # client secret URL parameter
|
||||
(r'([?&]key=)[^&]*', r'\1*****'), # API key URL parameter
|
||||
(r'([?&]code=)[^&]*', r'\1*****'), # auth code URL parameter
|
||||
|
||||
# Pattern match patterns that redact sensitive credentials based on known credential pattern
|
||||
(r'ya29.[0-9A-Za-z-_]+', '*****'), # Access token
|
||||
(r'1%2F%2F[0-9A-Za-z-_]{100}|1%2F%2F[0-9A-Za-z-_]{64}|1%2F%2F[0-9A-Za-z-_]{43}', '*****'), # Refresh token
|
||||
(r'4/[0-9A-Za-z-_]+', '*****'), # Auth code
|
||||
(r'GOCSPX-[0-9a-zA-Z-_]{28}', '*****'), # Client secret
|
||||
(r'AIza[0-9A-Za-z-_]{35}', '*****'), # API key
|
||||
(r'eyJ[a-zA-Z0-9\-_]+\.eyJ[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]*', '*****'), # JWT
|
||||
]
|
||||
|
||||
# Building address field map
|
||||
BUILDING_ADDRESS_FIELD_MAP = {
|
||||
'address': 'addressLines',
|
||||
|
||||
Reference in New Issue
Block a user