Compare commits

..

20 Commits
v4.92 ... v4.94

Author SHA1 Message Date
Jay Lee
cfd36c2836 GAM 4.94, pull in Ross changes in #1003 2019-08-30 11:45:52 -04:00
Jay Lee
7689ac7bed disable ssl verify on time sync so we know when clock is WAY off 2019-08-30 11:15:56 -04:00
Jay Lee
7a5ba99b36 Even better SA check 2019-08-30 11:02:42 -04:00
Ross Scroggs
8f4a40bc9a Add timeoffset option to gam version (#1002)
* Add timeoffset option to gam version

* Update timeOffset checking
2019-08-29 14:32:45 -04:00
Jay Lee
e3ab846d70 update user passwords 2019-08-27 14:28:04 -04:00
Jay Lee
29db574bc5 Merge branch 'master' of https://github.com/jay0lee/GAM 2019-08-27 10:19:48 -04:00
Jay Lee
4851d5b62f upgrade MUSL 2019-08-27 10:19:33 -04:00
Jay Lee
caef16bdee add email scope to SA, check serviceaccount verifies proper DwD and scopes for token 2019-08-27 10:18:36 -04:00
Ross Scroggs
1a0f9ab66a handle empty recoveryPhone (#999)
* handle empty recoveryPhone

* Test empty recoveryemail/recoveryphone

* Handle autoUpdateExpiration for CrOS
2019-08-21 15:03:05 -04:00
Ross Scroggs
021c3bfb13 Handle more errors with short URL oauth create (#998) 2019-08-18 17:34:55 -04:00
Jay Lee
b3dfa41df6 GAM user agent on short URL 2019-08-15 18:21:54 -04:00
Jay Lee
5f94263db2 Use _createHttpObj() for short URL 2019-08-15 18:15:56 -04:00
Jay Lee
68d8e46b4c force pip upgrades 2019-08-15 14:50:23 -04:00
Jay Lee
ed221b0d7b just use static recovery phone 2019-08-15 13:31:26 -04:00
Jay Lee
1243563cd4 try to make MacOS tr happy 2019-08-15 12:38:47 -04:00
Jay Lee
1170457a39 GAM 4.93, remove *MAX_RESULTS config options 2019-08-15 12:35:10 -04:00
Jay Lee
435ed9f568 use area code 212 always 2019-08-15 12:18:36 -04:00
Jay Lee
81884e48d0 Support recovery email/phone for users 2019-08-15 12:00:36 -04:00
Jay Lee
a7be6d233b confirm API call supports maxResults before checking value 2019-08-15 10:08:03 -04:00
Jay Lee
584ddba1a5 Dynamic maxResults from discovery or exception 2019-08-14 16:11:14 -04:00
8 changed files with 229 additions and 98 deletions

View File

@@ -5,7 +5,7 @@ env:
- BUILD_PYTHON_VERSION=3.7.4
- BUILD_OPENSSL_VERSION=1.1.1c
- PATCHELF_VERSION=0.9
- MUSL_VERSION=1.1.22
- MUSL_VERSION=1.1.23
- PYINSTALLER_VERSION=3.5
- secure: "FSKvLaiqhKz21SVgAQZI3bSX34Ffyev4l+R2G//QXNDu6UVQcuFsykzw+eZEG7fkhotXr8BMDL7xIkookiL8eLwUtcd/Z95HCjPBBHcmCSQleyvuuJBxdrQ9xldmiGLzMCYiumSH9OH4uJhQ39Yjnjsa8TK+PlTci6a/BTzlYyBSyDYDf7Iv/uhfQPDHL3pNwrQPHf4fL6/jcvo+uaPcv83AVZkNzZjjyoi9Aa+uh9xlbyHg11jp44463qqxoxTdYik3pYuXRBPjknjOGcnFHqn+QOVSdRQoiwbmT8xVuYuCzTv9THhuJ//i5u7s4y3Xyl7u17B3tdm86UlMpQHy/w9EsYaSBPOU4oPNomRtOnTSugh0v9ZBwptP5XfbslII/iA+LQdzTHhchn0W0CRyDqjOMSestWlrsq5NZJtBJTYHbebllOhEI7xbj9tY+re1zFWSPMOPgHJP23ovsdk3hD9OT93AzRHInCx5IxL6QvEgRhAancRuGkf2rGP0g/vX9fQ0Il3rNMSQxHB5CyHUBtUJ9nhU79YkMDZicD0jFMEwjWJO3itAp3ynoLXRgktgQCYUfgc9SpdWKD5SXLCYnSo22JD3D1P6h2EertRHaoKRLb+CRXQC/lM8uh/W+BjA2Xe6Vut2I/72ndjM+10T7E2xk1CFyCH37a5p8cH26Fs="
- secure: "J9380tGLOZWa7dSH1y5Il8T5JQpN6ad81gI6VR1HIU0svpRdjgikyDA7ca2MKYDUYYY9yVSkTV6gCl6iIU/9+SKaYugpP+tkvdGYkC2moJdcTgYM/WOnIK9ExQ3BPhN1neGxJjPTwKo1ft27mtZ2I5vuCiBwIcnKWLnKPyW3PD+mWpfqiLuEzkHoAh6G3jC4qbcCrZDeX/knE+PzqESUEi+8k1G8gYcSDWujba9ypSsqZ8T/MXagGla6l7y2Rz+/KZTJmFHwKAA10V+xPLVqxoiqi4ar66yUqy0BamwRXPcseI+ns3Q+4lUpMqVQ5GlRy7LF1xC8myjmcAexXk0F9hg+CMzewKI8UgmQH/ZJvQZEh8s6mW26+CqA4d3zMQkWaR0WtEtpiuH7AGHCflIqvEQ6UiG7ia3B8iZfW2wl0j/kqx4OuHkS3r0pWKVVIIvCj9Ow2BHP7SpiV1AcUGsVxzwbgTh67fitna3Z3c6Uj8ccQlNr7ZIt1az6Wf3w5njijkLOiBpQSLKunTTCTSge/JzBTKUcie3RE9vzirl58gUxAt36nDtPWnory+RttMZrOkBVbTeSxp+IUe8pNwLFPHABsafXsjkfzBOtFmm+0ZXWt2Rlog5NvlemJfQUWDlsL4g+BSakzN+4sIPKzSauWDHyaEeULY7Uprkil6c5zwo="
@@ -170,13 +170,15 @@ script:
for i in {01..20};
do echo $newbase-bulkuser-$i >> sample.csv;
done; fi
- if [ "$e2e" = true ]; then $gam create user $newuser firstname Travis lastname $jid password random travis.jid $jid; fi
- if [ "$e2e" = true ]; then $gam create user $newuser firstname Travis lastname $jid password random recoveryphone 12125121110 recoveryemail jay0lee@gmail.com travis.jid $jid; fi
- if [ "$e2e" = true ]; then $gam user $gam_user sendemail recipient $newuser subject "test message $newbase" message "Travis test message"; fi
- if [ "$e2e" = true ]; then $gam create group $newgroup name "Travis $jid group" description "This is a description" isarchived true; fi
- if [ "$e2e" = true ]; then $gam user $newuser add license gsuitebusiness; fi
- if [ "$e2e" = true ]; then $gam update group $newgroup add owner $gam_user; fi
- if [ "$e2e" = true ]; then $gam update group $newgroup add member $newuser; fi
- if [ "$e2e" = true ]; then $gam csv sample.csv gam create user ~~email~~ firstname "Travis Bulk" lastname ~~email~~ travis.jid $jid; fi
- if [ "$e2e" = true ]; then $gam csv sample.csv gam update user ~~email~~ recoveryphone 12125121110 recoveryemail jay0lee@gmail.com password random; fi
- if [ "$e2e" = true ]; then $gam csv sample.csv gam update user ~~email~~ recoveryphone "" recoveryemail ""; fi
- if [ "$e2e" = true ]; then $gam csv sample.csv gam user ~email add license gsuitebusiness; fi
- if [ "$e2e" = true ]; then $gam csv sample.csv gam user $gam_user sendemail recipient ~~email~~@pdl.jaylee.us subject "test message $newbase" message "Travis test message"; fi
- if [ "$e2e" = true ]; then $gam csv sample.csv gam update group $newgroup add member ~email; fi

View File

@@ -257,16 +257,20 @@ If an item contains spaces, it should be surrounded by ".
annotatedassetid|assedid|asset|
annotatedlocation|location|
annotateduser|user|
autoupdateexpiration|
bootmode|
cpustatusreports|
devicefiles|
deviceid|
diskvolumereports|
dockmacaddress|
ethernetmacaddress|
ethernetmacaddress0|
firmwareversion|
lastenrollmenttime|
lastsync|
macaddress|
manufacturedate|
meid|
model|
notes|
@@ -521,6 +525,8 @@ If an item contains spaces, it should be surrounded by ".
phones|phone|
posixaccounts|posix|
primaryemail|username|
recoveryemail|
recoveryphone|
relations|relation|
ssh|sshkeys|sshpublickeys|
suspended|
@@ -776,6 +782,8 @@ Specify a collection of Users by directly specifying them or by specifiying item
(note clear|([text_html|text_plain] <String>|(file <FileName> [charset <Charset>])))|
(org|ou|orgunitpath <OrgUnitPath>)
(password random|<Password>)|
(recoveryemail <EmailAddress>)|
(recoveryphone <string>)|
(suspended <Boolean>)|
(<SchemaName>.<FieldName> [multivalued|multivalue|value|multinonempty [type home|other|work|(custom <String>)]] <String>)
<UserMultiAttributes> ::=
@@ -799,7 +807,7 @@ Specify a collection of Users by directly specifying them or by specifiying item
<UserBasicAttribute>|
<UserMultiAttribute>
gam version [check|checkrc|simple|extended] [location <HostName>]
gam version [check|checkrc|simple|extended] [timeoffset] [location <HostName>]
gam help
gam batch <FileName>|- [charset <Charset>]
@@ -1295,7 +1303,7 @@ gam <UserTypeEntity> draftemail [recipient|to <EmailAddress>] [from <EmailAddres
gam <UserTypeEntity> importemail [recipient|to <EmailAddress>] [from <EmailAddress>]
[subject <String>] [(message <String>)|(file <FileName> [charset <Charset>])]
[labels <LabelNameList>] (header <String> <String>)*
[deleted] [date <Time>]
[deleted] [date <Time>]
[nevercheckspam] [processforcalendar]
gam <UserTypeEntity> insertemail [recipient|to <EmailAddress>] [from <EmailAddress>]
[subject <String>] [(message <String>)|(file <FileName> [charset <Charset>])]

View File

@@ -106,11 +106,11 @@ google_auth_httplib2.Request.__call__ = _request_with_user_agent(
google_auth_httplib2.AuthorizedHttp.request = _request_with_user_agent(
google_auth_httplib2.AuthorizedHttp.request)
def _createHttpObj(cache=None, override_min_tls=None, override_max_tls=None):
def _createHttpObj(cache=None, timeout=None, override_min_tls=None, override_max_tls=None):
tls_minimum_version = override_min_tls if override_min_tls else GC_Values[GC_TLS_MIN_VERSION]
tls_maximum_version = override_max_tls if override_max_tls else GC_Values[GC_TLS_MAX_VERSION]
return httplib2.Http(ca_certs=GC_Values[GC_CA_FILE], tls_maximum_version=tls_maximum_version, tls_minimum_version=tls_minimum_version,
cache=cache)
cache=cache, timeout=timeout)
def showUsage():
doGAMVersion(checkForArgs=False)
@@ -669,13 +669,8 @@ def SetGlobalVariables():
_getOldEnvVar(GC_CUSTOMER_ID, 'CUSTOMER_ID')
_getOldEnvVar(GC_CHARSET, 'GAM_CHARSET')
_getOldEnvVar(GC_NUM_THREADS, 'GAM_THREADS')
_getOldEnvVar(GC_ACTIVITY_MAX_RESULTS, 'GAM_ACTIVITY_MAX_RESULTS')
_getOldEnvVar(GC_AUTO_BATCH_MIN, 'GAM_AUTOBATCH')
_getOldEnvVar(GC_BATCH_SIZE, 'GAM_BATCH_SIZE')
_getOldEnvVar(GC_DEVICE_MAX_RESULTS, 'GAM_DEVICE_MAX_RESULTS')
_getOldEnvVar(GC_DRIVE_MAX_RESULTS, 'GAM_DRIVE_MAX_RESULTS')
_getOldEnvVar(GC_MEMBER_MAX_RESULTS, 'GAM_MEMBER_MAX_RESULTS')
_getOldEnvVar(GC_USER_MAX_RESULTS, 'GAM_USER_MAX_RESULTS')
_getOldEnvVar(GC_CSV_HEADER_FILTER, 'GAM_CSV_HEADER_FILTER')
_getOldEnvVar(GC_CSV_ROW_FILTER, 'GAM_CSV_ROW_FILTER')
_getOldEnvVar(GC_TLS_MIN_VERSION, 'GAM_TLS_MIN_VERSION')
@@ -725,6 +720,33 @@ def SetGlobalVariables():
GM_Globals[GM_CACHE_DISCOVERY_ONLY] = False
return True
def getLocalGoogleTimeOffset(testLocation='www.googleapis.com'):
localUTC = datetime.datetime.now(datetime.timezone.utc)
try:
# we disable SSL verify so we can still get time even if clock
# is way off. This could be spoofed / MitM but we'll fail for those
# situations everywhere else but here.
badhttp = _createHttpObj()
badhttp.disable_ssl_certificate_validation = True
googleUTC = dateutil.parser.parse(badhttp.request('https://'+testLocation, 'HEAD')[0]['date'])
offset = abs(localUTC-googleUTC).total_seconds()
days, remainder = divmod(offset, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
timeoff = []
if days:
timeoff.append('%d days' % days)
if hours:
timeoff.append('%d hours' % hours)
if minutes:
timeoff.append('%d minutes' % minutes)
if seconds:
timeoff.append('%d seconds' % seconds)
nicetime = ', '.join(timeoff)
return (offset, nicetime)
except (httplib2.ServerNotFoundError, RuntimeError, ValueError) as e:
systemErrorExit(4, str(e))
def doGAMCheckForUpdates(forceCheck=False):
def _gamLatestVersionNotAvailable():
@@ -742,8 +764,7 @@ def doGAMCheckForUpdates(forceCheck=False):
return
check_url = GAM_LATEST_RELEASE # latest full release
headers = {'Accept': 'application/vnd.github.v3.text+json'}
simplehttp = _createHttpObj()
simplehttp.timeout = 10
simplehttp = _createHttpObj(timeout=10)
try:
(_, c) = simplehttp.request(check_url, 'GET', headers=headers)
try:
@@ -780,9 +801,7 @@ def doGAMCheckForUpdates(forceCheck=False):
return
def doGAMVersion(checkForArgs=True):
force_check = False
simple = False
extended = False
force_check = extended = simple = timeOffset = False
testLocation = 'www.googleapis.com'
if checkForArgs:
i = 2
@@ -796,6 +815,10 @@ def doGAMVersion(checkForArgs=True):
i += 1
elif myarg == 'extended':
extended = True
timeOffset = True
i += 1
elif myarg == 'timeoffset':
timeOffset = True
i += 1
elif myarg == 'location':
testLocation = sys.argv[i+1]
@@ -810,6 +833,11 @@ def doGAMVersion(checkForArgs=True):
sys.version_info[1], sys.version_info[2], struct.calcsize('P')*8,
sys.version_info[3], googleapiclient.__version__,
platform.platform(), platform.machine(), GM_Globals[GM_GAM_PATH]))
if timeOffset:
offset, nicetime = getLocalGoogleTimeOffset(testLocation)
print('Your computer is %s off from Google\'s time.' % (nicetime))
if offset > MAX_LOCAL_GOOGLE_TIME_OFFSET:
systemErrorExit(4, 'Please fix your system clock.')
if force_check:
doGAMCheckForUpdates(forceCheck=True)
if extended:
@@ -859,7 +887,8 @@ def getSvcAcctCredentials(scopes, act_as):
GM_Globals[GM_OAUTH2SERVICE_JSON_DATA] = json.loads(json_string)
credentials = google.oauth2.service_account.Credentials.from_service_account_info(GM_Globals[GM_OAUTH2SERVICE_JSON_DATA])
credentials = credentials.with_scopes(scopes)
credentials = credentials.with_subject(act_as)
if act_as:
credentials = credentials.with_subject(act_as)
GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID] = GM_Globals[GM_OAUTH2SERVICE_JSON_DATA]['client_id']
return credentials
except (ValueError, KeyError):
@@ -1083,6 +1112,22 @@ def callGAPI(service, function,
except TypeError as e:
systemErrorExit(4, str(e))
def getPageSize(service, function, kwargs):
"""Gets maximum maxResults value for API call. Uses value from discovery if
it exists, otherwise value from MAX_RESULTS_API_EXCEPTIONS, otherwise None"""
method = getattr(service, function)
api_id = method(**kwargs).methodId
for resource in service._rootDesc.get('resources', {}).values():
for a_method in resource.get('methods', {}).values():
if a_method.get('id') == api_id:
if not a_method.get('parameters') or a_method['parameters'].get('pageSize') or not a_method['parameters'].get('maxResults'):
# make sure API call supports maxResults. For now we don't care to
# set pageSize since all known pageSize API calls have
# default pageSize == max pageSize
return
return {'maxResults': a_method['parameters']['maxResults'].get('maximum', MAX_RESULTS_API_EXCEPTIONS.get(api_id, None))}
def callGAPIpages(service, function, items='items',
page_message=None, message_attribute=None,
soft_errors=False, throw_reasons=None, retry_reasons=None,
@@ -1125,6 +1170,10 @@ def callGAPIpages(service, function, items='items',
Returns:
A list of all items received from all paged responses.
"""
if 'maxResults' not in kwargs and 'pageSize' not in kwargs:
page_key = getPageSize(service, function, kwargs)
if page_key:
kwargs.update(page_key)
all_items = []
page_token = None
total_items = 0
@@ -1312,7 +1361,6 @@ def buildGAPIObject(api):
GM_Globals[GM_CURRENT_API_USER] = None
credentials = getValidOauth2TxtCredentials()
credentials.user_agent = GAM_INFO
#http = credentials.authorize(httplib2.Http(cache=GM_Globals[GM_CACHE_DIR]))
http = google_auth_httplib2.AuthorizedHttp(credentials, _createHttpObj(cache=GM_Globals[GM_CACHE_DIR]))
service = getService(api, http)
if GC_Values[GC_DOMAIN]:
@@ -1469,7 +1517,39 @@ def buildGmailGAPIObject(user):
userEmail = convertUIDtoEmailAddress(user)
return (userEmail, buildGAPIServiceObject('gmail', userEmail))
def printPassFail(description, result):
padding = 80 - len(description) - 2
print(' {} {:>{padding}}'.format(description, result, padding=str(padding)))
def doCheckServiceAccount(users):
something_failed = False
print('Computer clock status:')
timeOffset, nicetime = getLocalGoogleTimeOffset()
if timeOffset < MAX_LOCAL_GOOGLE_TIME_OFFSET:
time_status = 'PASS'
else:
time_status = 'FAIL'
something_failed = True
printPassFail('Your computer clock differs from Google by %s' % nicetime, time_status)
oa2 = googleapiclient.discovery.build('oauth2', 'v1', _createHttpObj())
print('Service Account Private Key Authentication:')
# We are explicitly not doing DwD here, just confirming service account can auth
auth_error = ''
try:
credentials = getSvcAcctCredentials([USERINFO_EMAIL_SCOPE], None)
request = google_auth_httplib2.Request(_createHttpObj())
credentials.refresh(request)
sa_token_info = callGAPI(oa2, 'tokeninfo', access_token=credentials.token)
if sa_token_info:
sa_token_result = 'PASS'
else:
sa_token_result = 'FAIL'
something_failed = True
except google.auth.exceptions.RefreshError as e:
sa_token_result = 'FAIL'
something_failed = True
auth_error = str(e.args[0])
printPassFail('Authenticating...%s' % auth_error, sa_token_result)
all_scopes = []
for _, scopes in list(API_SCOPE_MAPPING.items()):
for scope in scopes:
@@ -1477,25 +1557,40 @@ def doCheckServiceAccount(users):
all_scopes.append(scope)
all_scopes.sort()
for user in users:
user = user.lower()
all_scopes_pass = True
print('User: %s' % (user))
oa2 = googleapiclient.discovery.build('oauth2', 'v1', _createHttpObj())
print('Domain-Wide Delegation authentication as %s:' % (user))
for scope in all_scopes:
try:
credentials = getSvcAcctCredentials([scope], user)
request = google_auth_httplib2.Request(_createHttpObj())
credentials.refresh(request)
result = 'PASS'
except (httplib2.ServerNotFoundError, RuntimeError) as e:
systemErrorExit(4, e)
except google.auth.exceptions.RefreshError:
# try with and without email scope
for scopes in [[scope, USERINFO_EMAIL_SCOPE], [scope]]:
try:
credentials = getSvcAcctCredentials(scopes, user)
credentials.refresh(request)
break
except (httplib2.ServerNotFoundError, RuntimeError) as e:
systemErrorExit(4, e)
except google.auth.exceptions.RefreshError:
continue
if credentials.token:
token_info = callGAPI(oa2, 'tokeninfo', access_token=credentials.token)
if scope in token_info.get('scope', '').split(' ') and \
user == token_info.get('email', user).lower():
result = 'PASS'
else:
result = 'FAIL'
all_scopes_pass = False
else:
result = 'FAIL'
all_scopes_pass = False
print(' Scope: {0:60} {1}'.format(scope, result))
printPassFail(scope, result)
service_account = GM_Globals[GM_OAUTH2SERVICE_ACCOUNT_CLIENT_ID]
if all_scopes_pass:
print('\nAll scopes passed!\nService account %s is fully authorized.' % service_account)
return
user_domain = user[user.find('@')+1:]
# Tack on email scope for more accurate checking
all_scopes.append('https://www.googleapis.com/auth/userinfo.email')
scopes_failed = '''Some scopes failed! Please go to:
https://admin.google.com/%s/AdminHome?#OGX:ManageOauthClients
@@ -2344,8 +2439,7 @@ def buildRoleIdToNameToIdMap():
cd = buildGAPIObject('directory')
result = callGAPIpages(cd.roles(), 'list', 'items',
customer=GC_Values[GC_CUSTOMER_ID],
fields='nextPageToken,items(roleId,roleName)',
maxResults=100)
fields='nextPageToken,items(roleId,roleName)')
GM_Globals[GM_MAP_ROLE_ID_TO_NAME] = {}
GM_Globals[GM_MAP_ROLE_NAME_TO_ID] = {}
for role in result:
@@ -2376,8 +2470,7 @@ def buildUserIdToNameMap():
cd = buildGAPIObject('directory')
result = callGAPIpages(cd.users(), 'list', 'users',
customer=GC_Values[GC_CUSTOMER_ID],
fields='nextPageToken,users(id,primaryEmail)',
maxResults=GC_Values[GC_USER_MAX_RESULTS])
fields='nextPageToken,users(id,primaryEmail)')
GM_Globals[GM_MAP_USER_ID_TO_NAME] = {}
for user in result:
GM_Globals[GM_MAP_USER_ID_TO_NAME][user['id']] = user['primaryEmail']
@@ -3162,7 +3255,10 @@ def changeCalendarAttendees(users):
continue
page_token = None
while True:
events_page = callGAPI(cal.events(), 'list', calendarId=user, pageToken=page_token, timeMin=start_date, timeMax=end_date, showDeleted=False, showHiddenInvitations=False)
events_page = callGAPI(cal.events(), 'list', calendarId=user,
pageToken=page_token, timeMin=start_date,
timeMax=end_date, showDeleted=False,
showHiddenInvitations=False)
print('Got %s items' % len(events_page.get('items', [])))
for event in events_page.get('items', []):
if event['status'] == 'cancelled':
@@ -3843,8 +3939,8 @@ def doCalendarPrintEvents():
systemErrorExit(2, '%s is not a valid argument for "gam calendar <email> printevents"' % sys.argv[i])
page_message = 'Got %%%%total_items%%%% events for %s' % calendarId
results = callGAPIpages(cal.events(), 'list', 'items', page_message=page_message,
maxResults=2500, calendarId=calendarId,
q=q, showDeleted=showDeleted, showHiddenInvitations=showHiddenInvitations,
calendarId=calendarId, q=q, showDeleted=showDeleted,
showHiddenInvitations=showHiddenInvitations,
timeMin=timeMin, timeMax=timeMax, timeZone=timeZone, updatedMin=updatedMin)
for result in results:
row = {'calendarId': calendarId}
@@ -4309,7 +4405,7 @@ def printDriveActivity(users):
feed = callGAPIpages(activity.activities(), 'list', 'activities',
page_message=page_message, source='drive.google.com', userId='me',
drive_ancestorId=drive_ancestorId, groupingStrategy='none',
drive_fileId=drive_fileId, pageSize=GC_Values[GC_ACTIVITY_MAX_RESULTS])
drive_fileId=drive_fileId)
for item in feed:
addRowTitlesToCSVfile(flatten_json(item['combinedEvent']), csvRows, titles)
writeCSVfile(csvRows, titles, 'Drive Activity', todrive)
@@ -4589,7 +4685,7 @@ def printDriveFileList(users):
page_message = ' Got %%%%total_items%%%% files for %s...\n' % user
feed = callGAPIpages(drive.files(), 'list', 'items',
page_message=page_message, soft_errors=True,
q=query, orderBy=orderBy, fields=fields, maxResults=GC_Values[GC_DRIVE_MAX_RESULTS])
q=query, orderBy=orderBy, fields=fields)
for f_file in feed:
a_file = {'Owner': user}
for attrib in f_file:
@@ -4643,7 +4739,7 @@ def doDriveSearch(drive, query=None, quiet=False):
page_message = None
files = callGAPIpages(drive.files(), 'list', 'items',
page_message=page_message,
q=query, fields='nextPageToken,items(id)', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS])
q=query, fields='nextPageToken,items(id)')
ids = list()
for f_file in files:
ids.append(f_file['id'])
@@ -4763,7 +4859,7 @@ def showDriveFileTree(users):
sys.stderr.write('Getting all files for %s...\n' % user)
page_message = ' Got %%%%total_items%%%% files for %s...\n' % user
feed = callGAPIpages(drive.files(), 'list', 'items', page_message=page_message,
q=query, orderBy=orderBy, fields='items(id,title,parents(id),mimeType),nextPageToken', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS])
q=query, orderBy=orderBy, fields='items(id,title,parents(id),mimeType),nextPageToken')
printDriveFolderContents(feed, root_folder, 0)
def deleteEmptyDriveFolders(users):
@@ -4777,7 +4873,7 @@ def deleteEmptyDriveFolders(users):
sys.stderr.write('Getting folders for %s...\n' % user)
page_message = ' Got %%%%total_items%%%% folders for %s...\n' % user
feed = callGAPIpages(drive.files(), 'list', 'items', page_message=page_message,
q=query, fields='items(title,id),nextPageToken', maxResults=GC_Values[GC_DRIVE_MAX_RESULTS])
q=query, fields='items(title,id),nextPageToken')
deleted_empty = False
for folder in feed:
children = callGAPI(drive.children(), 'list',
@@ -7551,6 +7647,14 @@ def getUserAttributes(i, cd, updateCmd):
keyword['value'] = sys.argv[i]
i += 1
appendItemToBodyList(body, 'keywords', keyword)
elif myarg in ['recoveryemail']:
body['recoveryEmail'] = sys.argv[i+1]
i += 2
elif myarg in ['recoveryphone']:
body['recoveryPhone'] = sys.argv[i+1]
if body['recoveryPhone'] and body['recoveryPhone'][0] != '+':
body['recoveryPhone'] = '+' + body['recoveryPhone']
i += 2
elif myarg == 'clearschema':
if not updateCmd:
systemErrorExit(2, '%s is not a valid create user argument.' % sys.argv[i])
@@ -7608,17 +7712,20 @@ def getUserAttributes(i, cd, updateCmd):
class ShortURLFlow(google_auth_oauthlib.flow.InstalledAppFlow):
def authorization_url(self, **kwargs):
long_url, state = super(ShortURLFlow, self).authorization_url(**kwargs)
simplehttp = httplib2.Http()
simplehttp.timeout = 10
simplehttp = _createHttpObj(timeout=10)
url_shortnr = 'https://gam-shortn.appspot.com/create'
headers = {'Content-Type': 'application/json'}
headers = {'Content-Type': 'application/json',
'user-agent': GAM_INFO}
try:
resp, content = simplehttp.request(url_shortnr, 'POST', '{"long_url": "%s"}' % long_url, headers=headers)
except:
return long_url, state
if resp.status != 200:
return long_url, state
return json.loads(content).get('short_url', ''), state
try:
return json.loads(content).get('short_url', long_url), state
except:
return long_url, state
def _run_oauth_flow(client_id, client_secret, scopes, access_type, login_hint=None):
client_config = {
@@ -9518,7 +9625,7 @@ def doUpdateGroup():
result = callGAPIpages(cd.members(), 'list', 'members',
page_message=page_message,
throw_reasons=GAPI_MEMBERS_THROW_REASONS,
groupKey=group, roles=listRoles, fields=listFields, maxResults=GC_Values[GC_MEMBER_MAX_RESULTS])
groupKey=group, roles=listRoles, fields=listFields)
if not result:
print('Group already has 0 members')
return
@@ -9699,7 +9806,10 @@ def doUpdateMobile():
query = resourceIds[6:]
fields = 'nextPageToken,mobiledevices(resourceId,email)'
page_message = 'Got %%total_items%% mobile devices...\n'
devices = callGAPIpages(cd.mobiledevices(), 'list', page_message=page_message, customerId=GC_Values[GC_CUSTOMER_ID], items='mobiledevices', query=query, fields=fields)
devices = callGAPIpages(cd.mobiledevices(), 'list',
page_message=page_message,
customerId=GC_Values[GC_CUSTOMER_ID],
items='mobiledevices', query=query, fields=fields)
else:
devices = [{'resourceId': resourceIds, 'email': ['not set']}]
doit = True
@@ -10104,9 +10214,13 @@ def doGetUserInfo(user_email=None):
else:
print('Last login time: %s' % user['lastLoginTime'])
if 'orgUnitPath' in user:
print('Google Org Unit Path: %s\n' % user['orgUnitPath'])
print('Google Org Unit Path: %s' % user['orgUnitPath'])
if 'thumbnailPhotoUrl' in user:
print('Photo URL: %s\n' % user['thumbnailPhotoUrl'])
if 'recoveryPhone' in user:
print('Recovery Phone: %s' % user['recoveryPhone'])
if 'recoveryEmail' in user:
print('Recovery Email: %s' % user['recoveryEmail'])
if 'notes' in user:
print('Notes:')
notes = user['notes']
@@ -10344,7 +10458,7 @@ def doGetGroupInfo(group_name=None):
for groupm in groups:
print(' %s: %s' % (groupm['name'], groupm['email']))
if getUsers:
members = callGAPIpages(cd.members(), 'list', 'members', groupKey=group_name, fields='nextPageToken,members(email,id,role,type)', maxResults=GC_Values[GC_MEMBER_MAX_RESULTS])
members = callGAPIpages(cd.members(), 'list', 'members', groupKey=group_name, fields='nextPageToken,members(email,id,role,type)')
print('Members:')
for member in members:
print(' %s: %s (%s)' % (member.get('role', ROLE_MEMBER).lower(), member.get('email', member['id']), member['type'].lower()))
@@ -10483,6 +10597,8 @@ def doGetCrosInfo():
print('CrOS Device: {0} ({1} of {2})'.format(deviceId, i, device_count))
if 'notes' in cros:
cros['notes'] = cros['notes'].replace('\n', '\\n')
if 'autoUpdateExpiration' in cros:
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(cros['autoUpdateExpiration'])
_checkTPMVulnerability(cros)
if guess_aue:
_guessAUE(cros, guessedAUEs)
@@ -10824,7 +10940,7 @@ def doGetOrgInfo(name=None, return_attrib=None):
page_message = 'Got %%total_items%% Users: %%first_item%% - %%last_item%%\n'
users = callGAPIpages(cd.users(), 'list', 'users', page_message=page_message,
message_attribute='primaryEmail', customer=GC_Values[GC_CUSTOMER_ID], query=orgUnitPathQuery(name, checkSuspended),
fields='users(primaryEmail,orgUnitPath),nextPageToken', maxResults=GC_Values[GC_USER_MAX_RESULTS])
fields='users(primaryEmail,orgUnitPath),nextPageToken')
if checkSuspended is None:
print('Users:')
elif not checkSuspended:
@@ -11067,7 +11183,7 @@ def doUndeleteUser():
else:
print('Looking up UID for %s...' % user)
deleted_users = callGAPIpages(cd.users(), 'list', 'users',
customer=GC_Values[GC_CUSTOMER_ID], showDeleted=True, maxResults=GC_Values[GC_USER_MAX_RESULTS])
customer=GC_Values[GC_CUSTOMER_ID], showDeleted=True)
matching_users = list()
for deleted_user in deleted_users:
if str(deleted_user['primaryEmail']).lower() == user:
@@ -11559,7 +11675,7 @@ def doPrintUsers():
all_users = callGAPIpages(cd.users(), 'list', 'users', page_message=page_message,
message_attribute='primaryEmail', customer=customer, domain=domain, fields=fields,
showDeleted=deleted_only, orderBy=orderBy, sortOrder=sortOrder, viewType=viewType,
query=query, projection=projection, customFieldMask=customFieldMask, maxResults=GC_Values[GC_USER_MAX_RESULTS])
query=query, projection=projection, customFieldMask=customFieldMask)
for user in all_users:
if email_parts and ('primaryEmail' in user):
user_email = user['primaryEmail']
@@ -11709,7 +11825,6 @@ def doPrintGroups():
titles = []
csvRows = []
addFieldTitleToCSVfile('email', GROUP_ARGUMENT_TO_PROPERTY_TITLE_MAP, cdfieldsList, fieldsTitles, titles)
maxResults = None
roles = []
getSettings = sortHeaders = False
while i < len(sys.argv):
@@ -11730,7 +11845,7 @@ def doPrintGroups():
usemember = None
i += 2
elif myarg == 'maxresults':
maxResults = getInteger(sys.argv[i+1], myarg, minVal=0)
# deprecated argument
i += 2
elif myarg == 'delimiter':
aliasDelimiter = memberDelimiter = sys.argv[i+1]
@@ -11812,8 +11927,7 @@ def doPrintGroups():
entityList = callGAPIpages(cd.groups(), 'list', 'groups',
page_message=page_message, message_attribute='email',
customer=customer, domain=usedomain, userKey=usemember, query=usequery,
fields='nextPageToken,groups({0})'.format(cdfields),
maxResults=maxResults)
fields='nextPageToken,groups({0})'.format(cdfields))
i = 0
count = len(entityList)
for groupEntity in entityList:
@@ -11833,7 +11947,7 @@ def doPrintGroups():
groupMembers = callGAPIpages(cd.members(), 'list', 'members',
page_message=page_message, message_attribute='email',
soft_errors=True,
groupKey=groupEmail, roles=listRoles, fields=listFields, maxResults=GC_Values[GC_MEMBER_MAX_RESULTS])
groupKey=groupEmail, roles=listRoles, fields=listFields)
if members:
membersList = []
membersCount = 0
@@ -12020,7 +12134,7 @@ def doPrintAliases():
page_message = 'Got %%num_items%% Users %%first_item%% - %%last_item%%\n'
all_users = callGAPIpages(cd.users(), 'list', 'users', page_message=page_message,
message_attribute='primaryEmail', customer=GC_Values[GC_CUSTOMER_ID], query=query,
fields='nextPageToken,users({0})'.format(','.join(userFields)), maxResults=GC_Values[GC_USER_MAX_RESULTS])
fields='nextPageToken,users({0})'.format(','.join(userFields)))
for user in all_users:
for alias in user.get('aliases', []):
csvRows.append({'Alias': alias, 'Target': user['primaryEmail'], 'TargetType': 'User'})
@@ -12109,7 +12223,7 @@ def doPrintGroupMembers():
validRoles, listRoles, listFields = _getRoleVerification(','.join(roles), fields)
group_members = callGAPIpages(cd.members(), 'list', 'members',
soft_errors=True,
groupKey=group_email, roles=listRoles, fields=listFields, maxResults=GC_Values[GC_MEMBER_MAX_RESULTS])
groupKey=group_email, roles=listRoles, fields=listFields)
for member in group_members:
if not _checkMemberRoleIsSuspended(member, validRoles, checkSuspended):
continue
@@ -12303,7 +12417,7 @@ def doPrintMobileDevices():
page_message = 'Got %%num_items%% Mobile Devices...\n'
all_mobile = callGAPIpages(cd.mobiledevices(), 'list', 'mobiledevices', page_message=page_message,
customerId=GC_Values[GC_CUSTOMER_ID], query=query, projection=projection, fields=fields,
orderBy=orderBy, sortOrder=sortOrder, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS])
orderBy=orderBy, sortOrder=sortOrder)
for mobile in all_mobile:
row = {}
for attrib in mobile:
@@ -12420,7 +12534,7 @@ def doPrintCrosActivity():
page_message = 'Got %%total_items%% CrOS Devices...\n'
all_cros = callGAPIpages(cd.chromeosdevices(), 'list', 'chromeosdevices', page_message=page_message,
query=query, customerId=GC_Values[GC_CUSTOMER_ID], projection='FULL',
fields=fields, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS], orgUnitPath=orgUnitPath)
fields=fields, orgUnitPath=orgUnitPath)
for cros in all_cros:
row = {}
for attrib in cros:
@@ -12601,7 +12715,7 @@ def doPrintCrosDevices():
page_message = 'Got %%total_items%% CrOS Devices...\n'
all_cros = callGAPIpages(cd.chromeosdevices(), 'list', 'chromeosdevices', page_message=page_message,
query=query, customerId=GC_Values[GC_CUSTOMER_ID], projection=projection, orgUnitPath=orgUnitPath,
orderBy=orderBy, sortOrder=sortOrder, fields=fields, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS])
orderBy=orderBy, sortOrder=sortOrder, fields=fields)
for cros in all_cros:
_checkTPMVulnerability(cros)
if guess_aue:
@@ -12610,6 +12724,8 @@ def doPrintCrosDevices():
for cros in all_cros:
if 'notes' in cros:
cros['notes'] = cros['notes'].replace('\n', '\\n')
if 'autoUpdateExpiration' in cros:
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(cros['autoUpdateExpiration'])
for cpuStatusReport in cros.get('cpuStatusReports', []):
for tempInfo in cpuStatusReport.get('cpuTemperatureInfo', []):
tempInfo['label'] = tempInfo['label'].strip()
@@ -12618,6 +12734,8 @@ def doPrintCrosDevices():
for cros in all_cros:
if 'notes' in cros:
cros['notes'] = cros['notes'].replace('\n', '\\n')
if 'autoUpdateExpiration' in cros:
cros['autoUpdateExpiration'] = utils.formatTimestampYMD(cros['autoUpdateExpiration'])
row = {}
for attrib in cros:
if attrib not in set(['kind', 'etag', 'tpmVersionInfo', 'recentUsers', 'activeTimeRanges',
@@ -13005,7 +13123,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, member_type=No
page_message = 'Got %%%%total_items%%%% %s...' % member_type_message
validRoles, listRoles, listFields = _getRoleVerification(member_type, 'nextPageToken,members(email,id,type,status)')
members = callGAPIpages(cd.members(), 'list', 'members', page_message=page_message,
groupKey=group, roles=listRoles, fields=listFields, maxResults=GC_Values[GC_MEMBER_MAX_RESULTS])
groupKey=group, roles=listRoles, fields=listFields)
users = []
for member in members:
if ((not groupUserMembersOnly) or (member['type'] == 'USER')) and _checkMemberRoleIsSuspended(member, validRoles, checkSuspended):
@@ -13028,7 +13146,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, member_type=No
page_message = 'Got %%total_items%% Users...'
members = callGAPIpages(cd.users(), 'list', 'users', page_message=page_message,
customer=GC_Values[GC_CUSTOMER_ID], fields='nextPageToken,users(primaryEmail,orgUnitPath)',
query=query, maxResults=GC_Values[GC_USER_MAX_RESULTS])
query=query)
ou = ou.lower()
for member in members:
if ou == member.get('orgUnitPath', '').lower():
@@ -13050,7 +13168,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, member_type=No
page_message = 'Got %%total_items%% Users...'
members = callGAPIpages(cd.users(), 'list', 'users', page_message=page_message,
customer=GC_Values[GC_CUSTOMER_ID], fields='nextPageToken,users(primaryEmail)',
query=query, maxResults=GC_Values[GC_USER_MAX_RESULTS])
query=query)
for member in members:
users.append(member['primaryEmail'])
if not silent:
@@ -13069,7 +13187,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, member_type=No
page_message = 'Got %%total_items%% Users...'
members = callGAPIpages(cd.users(), 'list', 'users', page_message=page_message,
customer=GC_Values[GC_CUSTOMER_ID], fields='nextPageToken,users(primaryEmail,suspended)',
query=query, maxResults=GC_Values[GC_USER_MAX_RESULTS])
query=query)
for member in members:
email = member['primaryEmail']
if (checkSuspended is None or checkSuspended == member['suspended']) and email not in usersSet:
@@ -13135,7 +13253,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, member_type=No
page_message = 'Got %%total_items%% Users...'
all_users = callGAPIpages(cd.users(), 'list', 'users', page_message=page_message,
customer=GC_Values[GC_CUSTOMER_ID], query=query,
fields='nextPageToken,users(primaryEmail)', maxResults=GC_Values[GC_USER_MAX_RESULTS])
fields='nextPageToken,users(primaryEmail)')
for member in all_users:
users.append(member['primaryEmail'])
if not silent:
@@ -13145,8 +13263,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, member_type=No
printGettingAllItems('CrOS Devices', None)
page_message = 'Got %%total_items%% CrOS Devices...'
all_cros = callGAPIpages(cd.chromeosdevices(), 'list', 'chromeosdevices', page_message=page_message,
customerId=GC_Values[GC_CUSTOMER_ID], fields='nextPageToken,chromeosdevices(deviceId)',
maxResults=GC_Values[GC_DEVICE_MAX_RESULTS])
customerId=GC_Values[GC_CUSTOMER_ID], fields='nextPageToken,chromeosdevices(deviceId)')
for member in all_cros:
users.append(member['deviceId'])
if not silent:
@@ -13171,7 +13288,7 @@ def getUsersToModify(entity_type=None, entity=None, silent=False, member_type=No
page_message = 'Got %%total_items%% CrOS Devices...'
members = callGAPIpages(cd.chromeosdevices(), 'list', 'chromeosdevices', page_message=page_message,
customerId=GC_Values[GC_CUSTOMER_ID], fields='nextPageToken,chromeosdevices(deviceId)',
query=query, maxResults=GC_Values[GC_DEVICE_MAX_RESULTS])
query=query)
for member in members:
deviceId = member['deviceId']
if deviceId not in usersSet:

View File

@@ -114,7 +114,6 @@ else
fi
echo "Upgrading pip packages..."
$pip freeze > upgrades.txt
$pip install --upgrade -r upgrades.txt
$pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 $pip install -U
$pip install --upgrade -r src/requirements.txt
$pip install --upgrade pyinstaller

View File

@@ -65,7 +65,6 @@ cd $whereibelong
export PATH=/usr/local/opt/python/libexec/bin:$PATH
$pip install --upgrade pip
$pip freeze > upgrades.txt
$pip install --upgrade -r upgrades.txt
$pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 $pip install -U
$pip install --upgrade -r src/requirements.txt
$pip install --upgrade pyinstaller

View File

@@ -21,8 +21,7 @@ until cinst -y wixtoolset; do echo "trying again..."; done
export PATH=$PATH:/c/Python37/scripts
cd $mypath
pip install --upgrade pip
pip freeze > upgrades.txt
pip install --upgrade -r upgrades.txt
pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 pip install -U
pip install --upgrade -r src/requirements.txt
#pip install --upgrade pyinstaller

View File

@@ -21,8 +21,7 @@ until cinst -y wixtoolset; do echo "trying again..."; done
export PATH=$PATH:/c/Python37/scripts
cd $mypath
pip install --upgrade pip
pip freeze > upgrades.txt
pip install --upgrade -r upgrades.txt
pip list --outdated --format=freeze | grep -v '^\-e' | cut -d = -f 1 | xargs -n1 pip install -U
pip install --upgrade -r src/requirements.txt
#pip install --upgrade pyinstaller
# Install PyInstaller from source and build bootloader

View File

@@ -6,7 +6,7 @@ import platform
import re
gam_author = 'Jay Lee <jay0lee@gmail.com>'
gam_version = '4.92'
gam_version = '4.94'
gam_license = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
GAM_URL = 'https://git.io/gam'
@@ -39,6 +39,8 @@ FN_LAST_UPDATE_CHECK_TXT = 'lastupdatecheck.txt'
MY_CUSTOMER = 'my_customer'
# See https://support.google.com/drive/answer/37603
MAX_GOOGLE_SHEET_CELLS = 5000000
MAX_LOCAL_GOOGLE_TIME_OFFSET = 30
SKUS = {
'1010010001': {
'product': '101001', 'aliases': ['identity', 'cloudidentity'], 'displayName': 'Cloud Identity'},
@@ -154,6 +156,8 @@ API_VER_MAPPING = {
'vault': 'v1',
}
USERINFO_EMAIL_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
API_SCOPE_MAPPING = {
'alertcenter': ['https://www.googleapis.com/auth/apps.alerts',],
'appsactivity': ['https://www.googleapis.com/auth/activity',
@@ -534,17 +538,21 @@ CROS_ARGUMENT_TO_PROPERTY_MAP = {
'annotateduser': ['annotatedUser',],
'asset': ['annotatedAssetId',],
'assetid': ['annotatedAssetId',],
'autoupdateexpiration': ['autoUpdateExpiration',],
'bootmode': ['bootMode',],
'cpustatusreports': ['cpuStatusReports',],
'devicefiles': ['deviceFiles',],
'deviceid': ['deviceId',],
'dockmacaddress': ['dockMacAddress',],
'diskvolumereports': ['diskVolumeReports',],
'ethernetmacaddress': ['ethernetMacAddress',],
'ethernetmacaddress0': ['ethernetMacAddress0',],
'firmwareversion': ['firmwareVersion',],
'lastenrollmenttime': ['lastEnrollmentTime',],
'lastsync': ['lastSync',],
'location': ['annotatedLocation',],
'macaddress': ['macAddress',],
'manufacturedate': ['manufactureDate',],
'meid': ['meid',],
'model': ['model',],
'notes': ['notes',],
@@ -586,12 +594,16 @@ CROS_SCALAR_PROPERTY_PRINT_ORDER = [
'osVersion',
'bootMode',
'meid',
'dockMacAddress',
'ethernetMacAddress',
'ethernetMacAddress0',
'macAddress',
'systemRamTotal',
'lastEnrollmentTime',
'orderNumber',
'manufactureDate',
'supportEndDate',
'autoUpdateExpiration',
'guessedAUEDate',
'guessedAUEModel',
'tpmVersionInfo',
@@ -757,8 +769,6 @@ GM_Globals = {
#
# Global variables defined by environment variables/signal files
#
# When retrieving lists of Google Drive activities from API, how many should be retrieved in each chunk
GC_ACTIVITY_MAX_RESULTS = 'activity_max_results'
# Automatically generate gam batch command if number of users specified in gam users xxx command exceeds this number
# Default: 0, don't automatically generate gam batch commands
GC_AUTO_BATCH_MIN = 'auto_batch_min'
@@ -780,16 +790,10 @@ GC_CUSTOMER_ID = 'customer_id'
GC_DEBUG_LEVEL = 'debug_level'
# ID Token decoded from OAuth 2.0 refresh token response. Includes hd (domain) and email of authorized user
GC_DECODED_ID_TOKEN = 'decoded_id_token'
# When retrieving lists of ChromeOS/Mobile devices from API, how many should be retrieved in each chunk
GC_DEVICE_MAX_RESULTS = 'device_max_results'
# Domain obtained from gam.cfg or oauth2.txt
GC_DOMAIN = 'domain'
# Google Drive download directory
GC_DRIVE_DIR = 'drive_dir'
# When retrieving lists of Drive files/folders from API, how many should be retrieved in each chunk
GC_DRIVE_MAX_RESULTS = 'drive_max_results'
# When retrieving lists of Google Group members from API, how many should be retrieved in each chunk
GC_MEMBER_MAX_RESULTS = 'member_max_results'
# If no_browser is False, writeCSVfile won't open a browser when todrive is set
# and doRequestOAuth prints a link and waits for the verification code when oauth2.txt is being created
GC_NO_BROWSER = 'no_browser'
@@ -813,8 +817,6 @@ GC_SHOW_COUNTS_MIN = 'show_counts_min'
GC_SHOW_GETTINGS = 'show_gettings'
# GAM config directory containing json discovery files
GC_SITE_DIR = 'site_dir'
# When retrieving lists of Users from API, how many should be retrieved in each chunk
GC_USER_MAX_RESULTS = 'user_max_results'
# CSV Columns GAM should show on CSV output
GC_CSV_HEADER_FILTER = 'csv_header_filter'
# CSV Rows GAM should filter
@@ -828,7 +830,6 @@ GC_CA_FILE = 'ca_file'
tls_min = "TLSv1_2" if hasattr(ssl.SSLContext(), "minimum_version") else None
GC_Defaults = {
GC_ACTIVITY_MAX_RESULTS: 100,
GC_AUTO_BATCH_MIN: 0,
GC_BATCH_SIZE: 50,
GC_CACHE_DIR: '',
@@ -839,11 +840,8 @@ GC_Defaults = {
GC_CUSTOMER_ID: MY_CUSTOMER,
GC_DEBUG_LEVEL: 0,
GC_DECODED_ID_TOKEN: '',
GC_DEVICE_MAX_RESULTS: 100,
GC_DOMAIN: '',
GC_DRIVE_DIR: '',
GC_DRIVE_MAX_RESULTS: 1000,
GC_MEMBER_MAX_RESULTS: 200,
GC_NO_BROWSER: False,
GC_NO_CACHE: False,
GC_NO_UPDATE_CHECK: False,
@@ -855,7 +853,6 @@ GC_Defaults = {
GC_SHOW_COUNTS_MIN: 0,
GC_SHOW_GETTINGS: True,
GC_SITE_DIR: '',
GC_USER_MAX_RESULTS: 500,
GC_CSV_HEADER_FILTER: '',
GC_CSV_ROW_FILTER: '',
GC_TLS_MIN_VERSION: tls_min,
@@ -880,7 +877,6 @@ GC_VAR_TYPE = 'type'
GC_VAR_LIMITS = 'lmit'
GC_VAR_INFO = {
GC_ACTIVITY_MAX_RESULTS: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (1, 500)},
GC_AUTO_BATCH_MIN: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (0, None)},
GC_BATCH_SIZE: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (1, 1000)},
GC_CACHE_DIR: {GC_VAR_TYPE: GC_TYPE_DIRECTORY},
@@ -891,11 +887,8 @@ GC_VAR_INFO = {
GC_CUSTOMER_ID: {GC_VAR_TYPE: GC_TYPE_STRING},
GC_DEBUG_LEVEL: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (0, None)},
GC_DECODED_ID_TOKEN: {GC_VAR_TYPE: GC_TYPE_STRING},
GC_DEVICE_MAX_RESULTS: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (1, 1000)},
GC_DOMAIN: {GC_VAR_TYPE: GC_TYPE_STRING},
GC_DRIVE_DIR: {GC_VAR_TYPE: GC_TYPE_DIRECTORY},
GC_DRIVE_MAX_RESULTS: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (1, 1000)},
GC_MEMBER_MAX_RESULTS: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (1, 10000)},
GC_NO_BROWSER: {GC_VAR_TYPE: GC_TYPE_BOOLEAN},
GC_NO_CACHE: {GC_VAR_TYPE: GC_TYPE_BOOLEAN},
GC_NO_UPDATE_CHECK: {GC_VAR_TYPE: GC_TYPE_BOOLEAN},
@@ -907,7 +900,6 @@ GC_VAR_INFO = {
GC_SHOW_COUNTS_MIN: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (0, None)},
GC_SHOW_GETTINGS: {GC_VAR_TYPE: GC_TYPE_BOOLEAN},
GC_SITE_DIR: {GC_VAR_TYPE: GC_TYPE_DIRECTORY},
GC_USER_MAX_RESULTS: {GC_VAR_TYPE: GC_TYPE_INTEGER, GC_VAR_LIMITS: (1, 500)},
GC_CSV_HEADER_FILTER: {GC_VAR_TYPE: GC_TYPE_HEADERFILTER},
GC_CSV_ROW_FILTER: {GC_VAR_TYPE: GC_TYPE_ROWFILTER},
GC_TLS_MIN_VERSION: {GC_VAR_TYPE: GC_TYPE_STRING},
@@ -1203,3 +1195,19 @@ LANGUAGE_CODES_MAP = {
'ur': 'ur', 'uz': 'uz', 'vi': 'vi', 'wo': 'wo', 'xh': 'xh', 'yi': 'yi', 'yo': 'yo', #Urdu, Uzbek, Vietnamese, Wolof, Xhosa, Yiddish, Yoruba
'zh-cn': 'zh-CN', 'zh-hk': 'zh-HK', 'zh-tw': 'zh-TW', 'zu': 'zu', #Chinese (Simplified), Chinese (Hong Kong/Traditional), Chinese (Taiwan/Traditional), Zulu
}
# maxResults exception values for API list calls. Should only be listed if:
# - discovery doc does not specify maximum value (we use maximum value if it
# exists, not this)
# - actual max API returns with maxResults=<bigNum> > default API returns
# when maxResults isn't specified (we should use default otherwise by not
# setting maxResults)
MAX_RESULTS_API_EXCEPTIONS = {
'calendar.acl.list': 250,
'calendar.calendarList.list': 250,
'calendar.events.list': 2500,
'calendar.settings.list': 250,
'directory.chromeosdevices.list': 200,
'drive.files.list': 1000,
}