mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-05 14:51:39 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a06776bbbd | ||
|
|
aecd725a71 | ||
|
|
ad8e9364e1 | ||
|
|
b812fef1c3 | ||
|
|
56371214b0 | ||
|
|
3669a86f41 | ||
|
|
4095bf63ef | ||
|
|
d75321ca8a | ||
|
|
c931e1cdd7 | ||
|
|
ea8cda72c7 | ||
|
|
f0bcd7888a | ||
|
|
6a08a66221 | ||
|
|
5e58edf598 | ||
|
|
1e79772ec1 | ||
|
|
3461ce053f | ||
|
|
9c84ce30e8 | ||
|
|
93ca63e133 | ||
|
|
e367c86fce | ||
|
|
34dc12994a | ||
|
|
df4de5ce4b | ||
|
|
ea630480b2 | ||
|
|
db1159cd0d | ||
|
|
ccf1dc0585 | ||
|
|
1cb96cf057 | ||
|
|
2bc8a114c1 | ||
|
|
7f183b9edc | ||
|
|
f86be17834 | ||
|
|
6854e3729a |
21
.travis.yml
21
.travis.yml
@@ -160,12 +160,14 @@ script:
|
||||
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 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 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
|
||||
- if [ "$e2e" = true ]; then $gam info group $newgroup; fi
|
||||
- if [ "$e2e" = true ]; then $gam user $gam_user check serviceaccount; fi
|
||||
@@ -173,7 +175,11 @@ script:
|
||||
- if [ "$e2e" = true ]; then $gam user $newuser show imap; fi
|
||||
- if [ "$e2e" = true ]; then $gam csv sample.csv gam user $newuser delegate to ~email; fi
|
||||
- if [ "$e2e" = true ]; then $gam user $newuser show delegates; fi
|
||||
- if [ "$e2e" = true ]; then $gam users "$newbase-bulkuser-01 $newbase-bulkuser-02 $newbase-bulkuser-03" delete messages query in:anywhere maxtodelete 99999 doit; fi
|
||||
- if [ "$e2e" = true ]; then $gam user $gam_user importemail subject "Travis import $newbase" message "This is a test import" labels IMPORTANT,UNREAD,INBOX,STARRED; fi
|
||||
- if [ "$e2e" = true ]; then $gam user $gam_user insertemail subject "Travis insert $newbase" file gam.py labels INBOX,UNREAD; fi # yep body is gam code
|
||||
- if [ "$e2e" = true ]; then $gam user $gam_user sendemail subject "Travis send $gam_user $newbase" file gam.py recipient admin@pdl.jaylee.us; fi
|
||||
- if [ "$e2e" = true ]; then $gam user $gam_user draftemail subject "Travis draft $newbase" message "Draft message test"; fi
|
||||
- if [ "$e2e" = true ]; then $gam users "$gam_user $newbase-bulkuser-01 $newbase-bulkuser-02 $newbase-bulkuser-03" delete messages query in:anywhere maxtodelete 99999 doit; fi
|
||||
- if [ "$e2e" = true ]; then $gam users "$newbase-bulkuser-04 $newbase-bulkuser-05 $newbase-bulkuser-06" trash messages query in:anywhere maxtotrash 99999 doit; fi
|
||||
- if [ "$e2e" = true ]; then $gam users "$newbase-bulkuser-07 $newbase-bulkuser-08 $newbase-bulkuser-09" modify messages query in:anywhere maxtomodify 99999 addlabel IMPORTANT addlabel STARRED doit; fi
|
||||
- if [ "$e2e" = true ]; then $gam create feature name Whiteboard-$newbase; fi
|
||||
@@ -182,9 +188,12 @@ script:
|
||||
- if [ "$e2e" = true ]; then $gam create resource $newresource "Resource Calendar $tstamp" capacity 25 features Whiteboard-$newbase,VC-$newbase building $newbuilding floor 15 type Room; fi
|
||||
- if [ "$e2e" = true ]; then $gam info resource $newresource; fi
|
||||
- if [ "$e2e" = true ]; then $gam user $newuser show filelist; fi
|
||||
- if [ "$e2e" = true ]; then $gam calendar $newuser update read domain; fi
|
||||
- if [ "$e2e" = true ]; then $gam calendar $newuser add editor $gam_user; fi
|
||||
- if [ "$e2e" = true ]; then $gam calendar $newuser showacl; fi
|
||||
- if [ "$e2e" = true ]; then $gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete id ~id; fi # clear ACLs
|
||||
- if [ "$e2e" = true ]; then $gam calendar $gam_user update read domain; fi
|
||||
- if [ "$e2e" = true ]; then $gam calendar $gam_user update freebusy default; fi
|
||||
- if [ "$e2e" = true ]; then $gam calendar $gam_user add editor $newuser; fi
|
||||
- if [ "$e2e" = true ]; then $gam calendar $gam_user showacl; fi
|
||||
- if [ "$e2e" = true ]; then $gam calendar $gam_user printacl | $gam csv - gam calendar $gam_user delete id ~id; fi
|
||||
- if [ "$e2e" = true ]; then $gam printer register; fi
|
||||
- if [ "$e2e" = true ]; then source travis/set_printer_csv_filter.sh; fi
|
||||
- if [ "$e2e" = true ]; then $gam print printers > printers.csv; fi
|
||||
@@ -194,10 +203,8 @@ script:
|
||||
- if [ "$e2e" = true ]; then $gam csv printers.csv gam info printer ~id; fi
|
||||
- if [ "$e2e" = true ]; then $gam print printjobs; fi
|
||||
- if [ "$e2e" = true ]; then $gam csv printers.csv gam printjob ~id fetch; fi
|
||||
- if [ "$e2e" = true ]; then $gam print printjobs | $gam csv - gam printjob ~id delete; fi
|
||||
- if [ "$e2e" = true ]; then $gam csv printers.csv gam delete printer ~id; fi
|
||||
#- if [ "$e2e" = true ]; then $gam calendar id:$newresource add editor $newuser; fi
|
||||
#- if [ "$e2e" = true ]; then $gam calendar id:$newresource update read domain; fi
|
||||
#- if [ "$e2e" = true ]; then $gam calendar id:$newresource showacl; fi
|
||||
- if [ "$e2e" = true ]; then $gam csv sample.csv gam user ~email add calendar id:$newresource; fi
|
||||
- if [ "$e2e" = true ]; then $gam delete resource $newresource; fi
|
||||
- if [ "$e2e" = true ]; then $gam delete feature Whiteboard-$newbase; fi
|
||||
|
||||
@@ -143,6 +143,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
<ASPID> ::= <String>
|
||||
<BuildingID> ::= <String>|id:<String>
|
||||
<CalendarACLRole> ::= editor|freebusy|freebusyreader|owner|reader|writer
|
||||
<CalendarACLRuleID> ::= user:<EmailAddress>|group:<EmailAddress>|domain:<DomainName>|default
|
||||
<CalendarColorIndex> ::= <Number in range 1-24>
|
||||
<CalendarItem> ::= <EmailAddress>|<String>
|
||||
<ChatRoom> ::= <String>
|
||||
@@ -798,7 +799,7 @@ Specify a collection of Users by directly specifying them or by specifiying item
|
||||
<UserBasicAttribute>|
|
||||
<UserMultiAttribute>
|
||||
|
||||
gam version [check] [simple]
|
||||
gam version [check|checkrc|simple|extended] [location <HostName>]
|
||||
gam help
|
||||
|
||||
gam batch <FileName>|- [charset <Charset>]
|
||||
@@ -939,7 +940,9 @@ gam print aliases|nicknames [todrive] [shownoneditable] [nogroups] [nousers] [(q
|
||||
gam calendar <CalendarItem> add <CalendarACLRole> ([user] <EmailAddress>)|(group <EmailAddress>)|(domain [<DomainName>])|default [sendnotifications <Boolean>]
|
||||
gam calendar <CalendarItem> update <CalendarACLRole> ([user] <EmailAddress>)|(group <EmailAddress>)|(domain [<DomainName>])|default [sendnotifications <Boolean>]
|
||||
gam calendar <CalendarItem> del|delete <CalendarACLRole> <EmailAddress>|(domain [<DomainName>])|default
|
||||
gam calendar <CalendarItem> del|delete id <CalendarACLRuleID>
|
||||
gam calendar <CalendarItem> showacl
|
||||
gam calendar <CalendarItem> printacl [todrive]
|
||||
|
||||
<EventNotificationAttribute> ::=
|
||||
notifyattendees|(sendnotifications <Boolean>)|(sendupdates all|enternalonly|none)
|
||||
@@ -1283,6 +1286,11 @@ gam <UserTypeEntity> untrash messages query <QueryGmail> [doit] [max_to_untrash|
|
||||
|
||||
gam <UserTypeEntity> show gmailprofile [todrive]
|
||||
|
||||
gam <UserTypeEntity> draftemail [recipient <EmailAddress>] [subject <String>] [(message <String>)|(file <FileName> [charset <Charset>])]
|
||||
gam <UserTypeEntity> importemail [recipient <EmailAddress>] [subject <String> [(message <String>)|(file <FileName> [charset <Charset>])]]
|
||||
gam <UserTypeEntity> insertemail [recipient <EmailAddress>] [subject <String>] [(message <String>)|(file <FileName> [charset <Charset>])]
|
||||
gam <UserTypeEntity> sendemail [recipient <EmailAddress>] [subject <String>] [(message <String>)|(file <FileName> [charset <Charset>])]
|
||||
|
||||
gam <UserTypeEntity> create|add delegate|delegates <EmailAddress>
|
||||
gam <UserTypeEntity> delegate|delegates to <EmailAddress>
|
||||
gam <UserTypeEntity> delete|del delegate|delegates <EmailAddress>
|
||||
|
||||
254
src/cros-aue-dates.json
Normal file
254
src/cros-aue-dates.json
Normal file
@@ -0,0 +1,254 @@
|
||||
{
|
||||
"acer ac700": "2016-08-01T00:00:00.000Z",
|
||||
"acer c7 chromebook": "2017-10-01T00:00:00.000Z",
|
||||
"acer c7 chromebook (c710)": "2017-10-01T00:00:00.000Z",
|
||||
"acer c720 chromebook": "2019-06-01T00:00:00.000Z",
|
||||
"acer c740 chromebook": "2019-06-01T00:00:00.000Z",
|
||||
"acer chromebase": "2020-08-01T00:00:00.000Z",
|
||||
"acer chromebase 24": "2021-06-01T00:00:00.000Z",
|
||||
"acer chromebook 11 (c720, c720p)": "2019-06-01T00:00:00.000Z",
|
||||
"acer chromebook 11 (c732, c732t, c732l, c732lt)": "2023-11-01T00:00:00.000Z",
|
||||
"acer chromebook 11 (c740)": "2020-06-01T00:00:00.000Z",
|
||||
"acer chromebook 11 (c771, c771t)": "2022-11-01T00:00:00.000Z",
|
||||
"acer chromebook 11 (cb3-111, c730, c730e)": "2019-08-01T00:00:00.000Z",
|
||||
"acer chromebook 11 (cb3-131, c735)": "2021-01-01T00:00:00.000Z",
|
||||
"acer chromebook 11 (cb311-8h, cb311-8ht)": "2023-11-01T00:00:00.000Z",
|
||||
"acer chromebook 11 n7 (c731, c731t)": "2022-01-01T00:00:00.000Z",
|
||||
"acer chromebook 13 (cb5-311)": "2019-09-01T00:00:00.000Z",
|
||||
"acer chromebook 13 (cb713-1w)": "2024-06-01T00:00:00.000Z",
|
||||
"acer chromebook 13(cb5-311, c810)": "2019-09-01T00:00:00.000Z",
|
||||
"acer chromebook 14 (cb3-431)": "2021-06-01T00:00:00.000Z",
|
||||
"acer chromebook 14 for work (cp5-471)": "2022-11-01T00:00:00.000Z",
|
||||
"acer chromebook 15 (c910 / cb5-571)": "2020-06-01T00:00:00.000Z",
|
||||
"acer chromebook 15 (cb3-531)": "2020-06-01T00:00:00.000Z",
|
||||
"acer chromebook 15 (cb3-532)": "2021-08-01T00:00:00.000Z",
|
||||
"acer chromebook 15 (cb315-1h,cb315-1ht)": "2023-11-01T00:00:00.000Z",
|
||||
"acer chromebook 15 (cb5-571, c910)": "2020-06-01T00:00:00.000Z",
|
||||
"acer chromebook 15 (cb515-1h,cb515-1ht)": "2023-11-01T00:00:00.000Z",
|
||||
"acer chromebook 311": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook 311 (c721, c733, c733u, c733t)": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook 315": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook 315 (cb315-2h)": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook 512 (c851, c851t)": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook 514": "2023-11-01T00:00:00.000Z",
|
||||
"acer chromebook 714 (cb714-1w / cb714-1wt)": "2024-06-01T00:00:00.000Z",
|
||||
"acer chromebook 715 (cb715-1w / cb715-1wt)": "2024-06-01T00:00:00.000Z",
|
||||
"acer chromebook r11 (cb5-132t, c738t)": "2021-06-01T00:00:00.000Z",
|
||||
"acer chromebook r13 (cb5-312t)": "2021-09-01T00:00:00.000Z",
|
||||
"acer chromebook spin 11 (cp311-h1, cp311-1hn)": "2023-11-01T00:00:00.000Z",
|
||||
"acer chromebook spin 11 (r751t)": "2023-11-01T00:00:00.000Z",
|
||||
"acer chromebook spin 13 (cp713-1wn)": "2024-06-01T00:00:00.000Z",
|
||||
"acer chromebook spin 15 (cp315)": "2023-11-01T00:00:00.000Z",
|
||||
"acer chromebook spin 311 (r721t)": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook spin 511": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook spin 511 (r752t, r752tn)": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook spin 512 (r851tn)": "2025-06-01T00:00:00.000Z",
|
||||
"acer chromebook tab 10": "2023-08-01T00:00:00.000Z",
|
||||
"acer chromebox": "2019-09-01T00:00:00.000Z",
|
||||
"acer chromebox cxi2": "2020-06-01T00:00:00.000Z",
|
||||
"acer chromebox cxi2 / cxv2": "2020-06-01T00:00:00.000Z",
|
||||
"acer chromebox cxi3": "2024-06-01T00:00:00.000Z",
|
||||
"aopen chromebase commercial": "2020-09-01T00:00:00.000Z",
|
||||
"aopen chromebase mini": "2022-02-01T00:00:00.000Z",
|
||||
"aopen chromebox commercial": "2020-09-01T00:00:00.000Z",
|
||||
"aopen chromebox commercial 2": "2024-06-01T00:00:00.000Z",
|
||||
"aopen chromebox mini": "2022-02-01T00:00:00.000Z",
|
||||
"asi chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"asus chromebit cs10": "2020-11-01T00:00:00.000Z",
|
||||
"asus chromebook c200": "2019-06-01T00:00:00.000Z",
|
||||
"asus chromebook c200ma": "2019-06-01T00:00:00.000Z",
|
||||
"asus chromebook c201pa": "2020-06-01T00:00:00.000Z",
|
||||
"asus chromebook c202sa": "2021-06-01T00:00:00.000Z",
|
||||
"asus chromebook c204": "2025-06-01T00:00:00.000Z",
|
||||
"asus chromebook c213na": "2023-11-01T00:00:00.000Z",
|
||||
"asus chromebook c223": "2023-11-01T00:00:00.000Z",
|
||||
"asus chromebook c300": "2019-08-01T00:00:00.000Z",
|
||||
"asus chromebook c300ma": "2019-08-01T00:00:00.000Z",
|
||||
"asus chromebook c300sa / c301sa": "2021-06-01T00:00:00.000Z",
|
||||
"asus chromebook c403": "2023-11-01T00:00:00.000Z",
|
||||
"asus chromebook c423": "2023-11-01T00:00:00.000Z",
|
||||
"asus chromebook c523": "2023-11-01T00:00:00.000Z",
|
||||
"asus chromebook flip c100pa": "2020-07-01T00:00:00.000Z",
|
||||
"asus chromebook flip c101pa": "2023-08-01T00:00:00.000Z",
|
||||
"asus chromebook flip c213": "2023-11-01T00:00:00.000Z",
|
||||
"asus chromebook flip c214": "2025-06-01T00:00:00.000Z",
|
||||
"asus chromebook flip c302": "2022-11-01T00:00:00.000Z",
|
||||
"asus chromebook flip c434": "2024-06-01T00:00:00.000Z",
|
||||
"asus chromebook tablet ct100": "2023-08-01T00:00:00.000Z",
|
||||
"asus chromebox (cn60)": "2019-09-01T00:00:00.000Z",
|
||||
"asus chromebox 2 (cn62)": "2021-06-01T00:00:00.000Z",
|
||||
"asus chromebox 3": "2024-06-01T00:00:00.000Z",
|
||||
"asus chromebox 3 (cn65)": "2024-06-01T00:00:00.000Z",
|
||||
"asus chromebox cn60": "2019-09-01T00:00:00.000Z",
|
||||
"asus chromebox cn62": "2021-06-01T00:00:00.000Z",
|
||||
"bobicus chromebook 11": "2020-06-01T00:00:00.000Z",
|
||||
"chromebook 11 (c730 / cb3-111)": "2019-08-01T00:00:00.000Z",
|
||||
"chromebook 11 (c735)": "2021-01-01T00:00:00.000Z",
|
||||
"chromebook 15 (cb515 - 1ht / 1h)": "2023-11-01T00:00:00.000Z",
|
||||
"chromebook 311 (c721)": "2025-06-01T00:00:00.000Z",
|
||||
"chromebook pcm-116e": "2020-06-01T00:00:00.000Z",
|
||||
"consumer chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"cr-48": "2015-12-01T00:00:00.000Z",
|
||||
"crambo chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"ctl chromebook j41 / j41t": "2023-11-01T00:00:00.000Z",
|
||||
"ctl chromebook nl7": "2023-11-01T00:00:00.000Z",
|
||||
"ctl chromebook nl7 / nl7t-360 / nl7tw-360": "2023-11-01T00:00:00.000Z",
|
||||
"ctl chromebook tab tx1": "2023-08-01T00:00:00.000Z",
|
||||
"ctl chromebook tablet tx1 for education": "2023-08-01T00:00:00.000Z",
|
||||
"ctl chromebox cbx1": "2024-06-01T00:00:00.000Z",
|
||||
"ctl j2 / j4 chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"ctl j5 chromebook": "2021-08-01T00:00:00.000Z",
|
||||
"ctl n6 education chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"ctl nl61 chromebook": "2021-08-01T00:00:00.000Z",
|
||||
"dell chromebook 11": "2019-06-01T00:00:00.000Z",
|
||||
"dell chromebook 11 (3120)": "2020-06-01T00:00:00.000Z",
|
||||
"dell chromebook 11 (3180)": "2022-05-01T00:00:00.000Z",
|
||||
"dell chromebook 11 (5190)": "2023-11-01T00:00:00.000Z",
|
||||
"dell chromebook 11 2-in-1 (3189)": "2022-05-01T00:00:00.000Z",
|
||||
"dell chromebook 11 2-in-1 (5190)": "2023-11-01T00:00:00.000Z",
|
||||
"dell chromebook 13 (3380)": "2022-11-01T00:00:00.000Z",
|
||||
"dell chromebook 13 (7310)": "2020-09-01T00:00:00.000Z",
|
||||
"dell chromebook 3100": "2025-06-01T00:00:00.000Z",
|
||||
"dell chromebook 3100 2-in-1": "2025-06-01T00:00:00.000Z",
|
||||
"dell chromebook 3400": "2025-06-01T00:00:00.000Z",
|
||||
"dell chromebox": "2019-09-01T00:00:00.000Z",
|
||||
"dell inspiron chromebook 14 2-in-1 (7486)": "2024-06-01T00:00:00.000Z",
|
||||
"edugear chromebook k": "2020-06-01T00:00:00.000Z",
|
||||
"edugear chromebook m": "2020-06-01T00:00:00.000Z",
|
||||
"edugear chromebook r": "2020-06-01T00:00:00.000Z",
|
||||
"edugear cmt chromebook": "2021-08-01T00:00:00.000Z",
|
||||
"edxis chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"edxis education chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"epik 11.6\" chromebook elb1101": "2020-06-01T00:00:00.000Z",
|
||||
"google chromebook pixel": "2018-06-01T00:00:00.000Z",
|
||||
"google chromebook pixel (2015)": "2020-06-01T00:00:00.000Z",
|
||||
"google cr-48": "2015-12-01T00:00:00.000Z",
|
||||
"google pixel slate": "2024-06-01T00:00:00.000Z",
|
||||
"google pixelbook": "2024-06-01T00:00:00.000Z",
|
||||
"haier chromebook 11": "2020-06-01T00:00:00.000Z",
|
||||
"haier chromebook 11 c": "2021-08-01T00:00:00.000Z",
|
||||
"haier chromebook 11 g2": "2020-09-01T00:00:00.000Z",
|
||||
"haier chromebook 11e": "2020-06-01T00:00:00.000Z",
|
||||
"hexa chromebook pi": "2020-06-01T00:00:00.000Z",
|
||||
"hisense chromebook 11": "2020-06-01T00:00:00.000Z",
|
||||
"hp chromebook 11 1100-1199 / hp chromebook 11 g1": "2018-10-01T00:00:00.000Z",
|
||||
"hp chromebook 11 2000-2099 / hp chromebook 11 g2": "2019-06-01T00:00:00.000Z",
|
||||
"hp chromebook 11 2100-2199 / hp chromebook 11 g3": "2020-06-01T00:00:00.000Z",
|
||||
"hp chromebook 11 2200-2299 / hp chromebook 11 g4/g4 ee": "2020-06-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g1": "2018-10-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g2": "2019-06-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g3": "2020-06-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g4/g4 ee": "2020-06-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g5": "2021-07-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g5 / hp chromebook 11-vxxx": "2021-07-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g5 ee": "2022-01-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g6 ee": "2023-11-01T00:00:00.000Z",
|
||||
"hp chromebook 11 g7 ee": "2025-06-01T00:00:00.000Z",
|
||||
"hp chromebook 11a g6 ee": "2025-06-01T00:00:00.000Z",
|
||||
"hp chromebook 13 g1": "2022-11-01T00:00:00.000Z",
|
||||
"hp chromebook 14": "2019-06-01T00:00:00.000Z",
|
||||
"hp chromebook 14 / hp chromebook 14 g5": "2023-11-01T00:00:00.000Z",
|
||||
"hp chromebook 14 ak000-099 / hp chromebook 14 g4": "2021-09-01T00:00:00.000Z",
|
||||
"hp chromebook 14 db0000-db0999": "2025-06-01T00:00:00.000Z",
|
||||
"hp chromebook 14 g3": "2019-10-01T00:00:00.000Z",
|
||||
"hp chromebook 14 g4": "2021-09-01T00:00:00.000Z",
|
||||
"hp chromebook 14 g5": "2023-11-01T00:00:00.000Z",
|
||||
"hp chromebook 14 x000-x999 / hp chromebook 14 g3": "2019-10-01T00:00:00.000Z",
|
||||
"hp chromebook 14a g5": "2025-06-01T00:00:00.000Z",
|
||||
"hp chromebook 15 g1": "2024-06-01T00:00:00.000Z",
|
||||
"hp chromebook x2 ": "2024-06-01T00:00:00.000Z",
|
||||
"hp chromebook x360 11 g1 ee": "2023-11-01T00:00:00.000Z",
|
||||
"hp chromebook x360 11 g2 ee": "2025-06-01T00:00:00.000Z",
|
||||
"hp chromebook x360 14": "2024-06-01T00:00:00.000Z",
|
||||
"hp chromebook x360 14 g1": "2024-06-01T00:00:00.000Z",
|
||||
"hp chromebox cb1-(000-099) / hp chromebox g1/ hp chromebox for meetings": "2019-09-01T00:00:00.000Z",
|
||||
"hp chromebox g1": "2019-09-01T00:00:00.000Z",
|
||||
"hp chromebox g2": "2024-06-01T00:00:00.000Z",
|
||||
"hp pavilion chromebook 14": "2018-02-01T00:00:00.000Z",
|
||||
"jp sa couto chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"lava xolo chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"lenovo 100e chromebook": "2023-11-01T00:00:00.000Z",
|
||||
"lenovo 100e chromebook 2nd gen": "2025-06-01T00:00:00.000Z",
|
||||
"lenovo 100e chromebook 2nd gen mtk": "2025-06-01T00:00:00.000Z",
|
||||
"lenovo 100s chromebook": "2020-09-01T00:00:00.000Z",
|
||||
"lenovo 14e chromebook": "2025-06-01T00:00:00.000Z",
|
||||
"lenovo 300e chromebook": "2025-06-01T00:00:00.000Z",
|
||||
"lenovo 300e chromebook 2nd gen": "2025-06-01T00:00:00.000Z",
|
||||
"lenovo 300e chromebook 2nd gen mtk": "2025-06-01T00:00:00.000Z",
|
||||
"lenovo 500e chromebook": "2023-11-01T00:00:00.000Z",
|
||||
"lenovo 500e chromebook 2nd gen": "2025-06-01T00:00:00.000Z",
|
||||
"lenovo chromebook c330": "2022-06-01T00:00:00.000Z",
|
||||
"lenovo chromebook s330": "2022-06-01T00:00:00.000Z",
|
||||
"lenovo flex 11 chromebook": "2022-06-01T00:00:00.000Z",
|
||||
"lenovo ideapad c330 chromebook": "2022-06-01T00:00:00.000Z",
|
||||
"lenovo ideapad s330 chromebook": "2022-06-01T00:00:00.000Z",
|
||||
"lenovo n20 chromebook": "2019-06-01T00:00:00.000Z",
|
||||
"lenovo n21 chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"lenovo n22 chromebook": "2021-06-01T00:00:00.000Z",
|
||||
"lenovo n23 chromebook": "2021-06-01T00:00:00.000Z",
|
||||
"lenovo n23 yoga chromebook": "2022-06-01T00:00:00.000Z",
|
||||
"lenovo n42 chromebook": "2021-06-01T00:00:00.000Z",
|
||||
"lenovo thinkcentre chromebox": "2020-06-01T00:00:00.000Z",
|
||||
"lenovo thinkpad 11e 3rd gen chromebook": "2021-06-01T00:00:00.000Z",
|
||||
"lenovo thinkpad 11e 4th gen chromebook": "2023-11-01T00:00:00.000Z",
|
||||
"lenovo thinkpad 11e chromebook": "2019-06-01T00:00:00.000Z",
|
||||
"lenovo thinkpad 11e chromebook (4th gen)/lenovo thinkpad yoga 11e chromebook (4th gen)": "2023-11-01T00:00:00.000Z",
|
||||
"lenovo thinkpad 13": "2022-11-01T00:00:00.000Z",
|
||||
"lenovo thinkpad x131e chromebook": "2018-06-01T00:00:00.000Z",
|
||||
"lenovo yoga c630 chromebook": "2024-06-01T00:00:00.000Z",
|
||||
"lg chromebase (22cb25s)": "2020-06-01T00:00:00.000Z",
|
||||
"lg chromebase (22cv241)": "2019-06-01T00:00:00.000Z",
|
||||
"lumos education chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"m&a chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"mecer chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"mecer v2 chromebook": "2021-08-01T00:00:00.000Z",
|
||||
"medion chromebook akoya s2013 ": "2020-06-01T00:00:00.000Z",
|
||||
"medion chromebook s2015": "2020-06-01T00:00:00.000Z",
|
||||
"multilaser chromebook m11c": "2021-08-01T00:00:00.000Z",
|
||||
"ncomputing chromebook cx100": "2020-06-01T00:00:00.000Z",
|
||||
"ncomputing chromebook cx110": "2020-06-01T00:00:00.000Z",
|
||||
"nexian chromebook 11.6\"": "2020-06-01T00:00:00.000Z",
|
||||
"pcmerge chromebook al116": "2023-11-01T00:00:00.000Z",
|
||||
"pcmerge chromebookpcm-116e/pcm-116eb": "2020-06-01T00:00:00.000Z",
|
||||
"pcmerge chromebookpcm-116t-432b": "2021-08-01T00:00:00.000Z",
|
||||
"poin2 chromebook 11": "2020-06-01T00:00:00.000Z",
|
||||
"poin2 chromebook 11c": "2022-03-01T00:00:00.000Z",
|
||||
"poin2 chromebook 14": "2022-03-01T00:00:00.000Z",
|
||||
"positivo chromebook c216b": "2021-08-01T00:00:00.000Z",
|
||||
"positivo chromebook ch1190": "2020-06-01T00:00:00.000Z",
|
||||
"prowise 11.6\" entry line chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"prowise chromebook eduline": "2023-11-01T00:00:00.000Z",
|
||||
"prowise chromebook entryline": "2020-06-01T00:00:00.000Z",
|
||||
"prowise chromebook proline": "2021-08-01T00:00:00.000Z",
|
||||
"prowise proline chromebook": "2021-08-01T00:00:00.000Z",
|
||||
"rgs education chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"samsung chromebook": "2018-07-01T00:00:00.000Z",
|
||||
"samsung chromebook - xe303": "2018-07-01T00:00:00.000Z",
|
||||
"samsung chromebook 2 11\"": "2019-06-01T00:00:00.000Z",
|
||||
"samsung chromebook 2 11\" - xe500c12": "2020-06-01T00:00:00.000Z",
|
||||
"samsung chromebook 2 13\"": "2019-06-01T00:00:00.000Z",
|
||||
"samsung chromebook 3": "2021-06-01T00:00:00.000Z",
|
||||
"samsung chromebook plus": "2023-08-01T00:00:00.000Z",
|
||||
"samsung chromebook plus (v2)": "2024-06-01T00:00:00.000Z",
|
||||
"samsung chromebook pro": "2022-11-01T00:00:00.000Z",
|
||||
"samsung chromebook series 5": "2016-06-01T00:00:00.000Z",
|
||||
"samsung chromebook series 5 550": "2017-05-01T00:00:00.000Z",
|
||||
"samsung chromebox series 3": "2018-03-01T00:00:00.000Z",
|
||||
"sector 5 e1 rugged chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"sector 5 e3 chromebook": "2023-11-01T00:00:00.000Z",
|
||||
"senkatel c1101 chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"thinkpad 11e chromebook 3rd gen (yoga/clamshell)": "2021-06-01T00:00:00.000Z",
|
||||
"thinkpad 13 chromebook": "2022-11-01T00:00:00.000Z",
|
||||
"toshiba chromebook": "2019-06-01T00:00:00.000Z",
|
||||
"toshiba chromebook 2": "2020-06-01T00:00:00.000Z",
|
||||
"toshiba chromebook 2 (2015 edition)": "2020-09-01T00:00:00.000Z",
|
||||
"true idc chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"true idc chromebook 11": "2020-06-01T00:00:00.000Z",
|
||||
"videonet chromebook": "2020-06-01T00:00:00.000Z",
|
||||
"videonet chromebook bl10": "2020-06-01T00:00:00.000Z",
|
||||
"viewsonic nmp660 chromebox": "2024-06-01T00:00:00.000Z",
|
||||
"viglen chromebook 11": "2020-06-01T00:00:00.000Z",
|
||||
"viglen chromebook 11c": "2023-11-01T00:00:00.000Z",
|
||||
"viglen chromebook 360": "2021-08-01T00:00:00.000Z",
|
||||
"xolo chromebook": "2020-06-01T00:00:00.000Z"
|
||||
}
|
||||
307
src/gam.py
307
src/gam.py
@@ -27,6 +27,7 @@ import configparser
|
||||
import csv
|
||||
import datetime
|
||||
import difflib
|
||||
from email import message_from_string
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
@@ -50,7 +51,6 @@ import uuid
|
||||
import webbrowser
|
||||
import zipfile
|
||||
import http.client as http_client
|
||||
from email.mime.text import MIMEText
|
||||
from multiprocessing import Pool
|
||||
from multiprocessing import freeze_support
|
||||
from urllib.parse import urlencode, urlparse
|
||||
@@ -113,32 +113,6 @@ def _createHttpObj(cache=None, override_min_tls=None, override_max_tls=None):
|
||||
return httplib2.Http(tls_maximum_version=tls_maximum_version, tls_minimum_version=tls_minimum_version,
|
||||
cache=cache)
|
||||
|
||||
# Override google_auth_oauthlib classes so we use PKCE
|
||||
# Remove once https://github.com/googleapis/google-auth-library-python-oauthlib/pull/42
|
||||
# is landed and released.
|
||||
def _authorization_url(self, **kwargs):
|
||||
kwargs.setdefault('access_type', 'offline')
|
||||
rnd = SystemRandom()
|
||||
random_verifier = [rnd.choice(URL_SAFE_CHARS) for _ in range(128)]
|
||||
self.code_verifier = ''.join(random_verifier)
|
||||
code_hash = hashlib.sha256()
|
||||
code_hash.update(str.encode(self.code_verifier))
|
||||
unencoded_challenge = code_hash.digest()
|
||||
b64_challenge = base64.urlsafe_b64encode(unencoded_challenge)
|
||||
code_challenge = b64_challenge.decode().split('=')[0]
|
||||
kwargs.setdefault('code_challenge', code_challenge)
|
||||
kwargs.setdefault('code_challenge_method', 'S256')
|
||||
url, state = self.oauth2session.authorization_url(self.client_config['auth_uri'], **kwargs)
|
||||
return url, state
|
||||
|
||||
def _fetch_token(self, **kwargs):
|
||||
kwargs.setdefault('client_secret', self.client_config['client_secret'])
|
||||
kwargs.setdefault('code_verifier', self.code_verifier)
|
||||
return self.oauth2session.fetch_token(self.client_config['token_uri'], **kwargs)
|
||||
|
||||
google_auth_oauthlib.flow.Flow.authorization_url = _authorization_url
|
||||
google_auth_oauthlib.flow.Flow.fetch_token = _fetch_token
|
||||
|
||||
def showUsage():
|
||||
doGAMVersion(checkForArgs=False)
|
||||
print('''
|
||||
@@ -630,7 +604,7 @@ def SetGlobalVariables():
|
||||
|
||||
ROW_FILTER_COMP_PATTERN = re.compile(r'^(date|time|count)\s*([<>]=?|=|!=)\s*(.+)$', re.IGNORECASE)
|
||||
ROW_FILTER_BOOL_PATTERN = re.compile(r'^(boolean):(.+)$', re.IGNORECASE)
|
||||
ROW_FILTER_RE_PATTERN = re.compile(r'^(regex):(.+)$', re.IGNORECASE)
|
||||
ROW_FILTER_RE_PATTERN = re.compile(r'^(regex|notregex):(.+)$', re.IGNORECASE)
|
||||
|
||||
def _getCfgRowFilter(itemName):
|
||||
value = GC_Defaults[itemName]
|
||||
@@ -673,7 +647,7 @@ def SetGlobalVariables():
|
||||
continue
|
||||
except re.error as e:
|
||||
systemErrorExit(3, 'Item: {0}, Value: "{1}": "{2}", Invalid RE: {3}'.format(itemName, column, filterStr, e))
|
||||
systemErrorExit(3, 'Item: {0}, Value: "{1}": {2}, Expected: (date|time|count<Operator><Value>) or (boolean:true|false) or (regex:<RegularExpression>)'.format(itemName, column, filterStr))
|
||||
systemErrorExit(3, 'Item: {0}, Value: "{1}": {2}, Expected: (date|time|count<Operator><Value>) or (boolean:true|false) or (regex|notregex:<RegularExpression>)'.format(itemName, column, filterStr))
|
||||
return rowFilters
|
||||
except (TypeError, ValueError) as e:
|
||||
systemErrorExit(3, 'Item: {0}, Value: "{1}", Failed to parse as JSON: {2}'.format(itemName, value, str(e)))
|
||||
@@ -848,10 +822,17 @@ def _getServerTLSUsed(location):
|
||||
conn = 'https:%s' % netloc
|
||||
httpc = _createHttpObj()
|
||||
headers = {'user-agent': GAM_INFO}
|
||||
try:
|
||||
httpc.request(url, headers=headers)
|
||||
except (httplib2.ServerNotFoundError, RuntimeError) as e:
|
||||
systemErrorExit(4, e)
|
||||
retries = 5
|
||||
for n in range(1, retries+1):
|
||||
try:
|
||||
httpc.request(url, headers=headers)
|
||||
break
|
||||
except (httplib2.ServerNotFoundError, RuntimeError) as e:
|
||||
if n != retries:
|
||||
httpc.connections = {}
|
||||
waitOnFailure(n, retries, str(e))
|
||||
continue
|
||||
systemErrorExit(4, str(e))
|
||||
cipher_name, tls_ver, _ = httpc.connections[conn].sock.cipher()
|
||||
return tls_ver, cipher_name
|
||||
|
||||
@@ -1092,7 +1073,13 @@ def callGAPI(service, function,
|
||||
service._http.cache = None
|
||||
continue
|
||||
systemErrorExit(4, str(e))
|
||||
except (TypeError, httplib2.ServerNotFoundError, RuntimeError) as e:
|
||||
except (httplib2.ServerNotFoundError, RuntimeError) as e:
|
||||
if n != retries:
|
||||
service._http.connections = {}
|
||||
waitOnFailure(n, retries, str(e))
|
||||
continue
|
||||
systemErrorExit(4, str(e))
|
||||
except TypeError as e:
|
||||
systemErrorExit(4, str(e))
|
||||
|
||||
def callGAPIpages(service, function, items='items',
|
||||
@@ -1242,7 +1229,7 @@ def getOauth2TxtStorageCredentials():
|
||||
oauth_data = json.loads(oauth_string)
|
||||
creds = google.oauth2.credentials.Credentials.from_authorized_user_file(GC_Values[GC_OAUTH2_TXT])
|
||||
creds.token = oauth_data.get('token', oauth_data.get('auth_token', ''))
|
||||
creds._id_token = oauth_data.get('id_token', None)
|
||||
creds._id_token = oauth_data.get('id_token_jwt', oauth_data.get('id_token', None))
|
||||
token_expiry = oauth_data.get('token_expiry', '1970-01-01T00:00:01Z')
|
||||
creds.expiry = datetime.datetime.strptime(token_expiry, '%Y-%m-%dT%H:%M:%SZ')
|
||||
GC_Values[GC_DECODED_ID_TOKEN] = oauth_data.get('decoded_id_token', '')
|
||||
@@ -1252,11 +1239,19 @@ def getValidOauth2TxtCredentials(force_refresh=False):
|
||||
"""Gets OAuth2 credentials which are guaranteed to be fresh and valid."""
|
||||
credentials = getOauth2TxtStorageCredentials()
|
||||
if (credentials and credentials.expired) or force_refresh:
|
||||
try:
|
||||
credentials.refresh(google_auth_httplib2.Request(_createHttpObj()))
|
||||
writeCredentials(credentials)
|
||||
except google.auth.exceptions.RefreshError as e:
|
||||
systemErrorExit(18, str(e))
|
||||
retries = 3
|
||||
for n in range(1, retries+1):
|
||||
try:
|
||||
credentials.refresh(google_auth_httplib2.Request(_createHttpObj()))
|
||||
writeCredentials(credentials)
|
||||
break
|
||||
except google.auth.exceptions.RefreshError as e:
|
||||
systemErrorExit(18, str(e))
|
||||
except (google.auth.exceptions.TransportError, httplib2.ServerNotFoundError, RuntimeError) as e:
|
||||
if n != retries:
|
||||
waitOnFailure(n, retries, str(e))
|
||||
continue
|
||||
systemErrorExit(4, str(e))
|
||||
elif credentials is None or not credentials.valid:
|
||||
doRequestOAuth()
|
||||
credentials = getOauth2TxtStorageCredentials()
|
||||
@@ -1283,6 +1278,10 @@ def getService(api, http):
|
||||
http.cache = None
|
||||
return service
|
||||
except (httplib2.ServerNotFoundError, RuntimeError) as e:
|
||||
if n != retries:
|
||||
http.connections = {}
|
||||
waitOnFailure(n, retries, str(e))
|
||||
continue
|
||||
systemErrorExit(4, str(e))
|
||||
except (googleapiclient.errors.InvalidJsonError, KeyError, ValueError) as e:
|
||||
http.cache = None
|
||||
@@ -1410,17 +1409,24 @@ def buildGAPIServiceObject(api, act_as, showAuthError=True):
|
||||
GM_Globals[GM_CURRENT_API_SCOPES] = API_SCOPE_MAPPING[api]
|
||||
credentials = getSvcAcctCredentials(GM_Globals[GM_CURRENT_API_SCOPES], act_as)
|
||||
request = google_auth_httplib2.Request(http)
|
||||
try:
|
||||
credentials.refresh(request)
|
||||
service._http = google_auth_httplib2.AuthorizedHttp(credentials, http=http)
|
||||
except (httplib2.ServerNotFoundError, RuntimeError) as e:
|
||||
systemErrorExit(4, e)
|
||||
except google.auth.exceptions.RefreshError as e:
|
||||
if isinstance(e.args, tuple):
|
||||
e = e.args[0]
|
||||
if showAuthError:
|
||||
stderrErrorMsg('User {0}: {1}'.format(GM_Globals[GM_CURRENT_API_USER], str(e)))
|
||||
return handleOAuthTokenError(str(e), True)
|
||||
retries = 3
|
||||
for n in range(1, retries+1):
|
||||
try:
|
||||
credentials.refresh(request)
|
||||
service._http = google_auth_httplib2.AuthorizedHttp(credentials, http=http)
|
||||
break
|
||||
except (httplib2.ServerNotFoundError, RuntimeError) as e:
|
||||
if n != retries:
|
||||
http.connections = {}
|
||||
waitOnFailure(n, retries, str(e))
|
||||
continue
|
||||
systemErrorExit(4, e)
|
||||
except google.auth.exceptions.RefreshError as e:
|
||||
if isinstance(e.args, tuple):
|
||||
e = e.args[0]
|
||||
if showAuthError:
|
||||
stderrErrorMsg('User {0}: {1}'.format(GM_Globals[GM_CURRENT_API_USER], str(e)))
|
||||
return handleOAuthTokenError(str(e), True)
|
||||
return service
|
||||
|
||||
def buildAlertCenterGAPIObject(user):
|
||||
@@ -2053,11 +2059,11 @@ def doGetDomainInfo():
|
||||
domainName = sys.argv[3]
|
||||
result = callGAPI(cd.domains(), 'get', customer=GC_Values[GC_CUSTOMER_ID], domainName=domainName)
|
||||
if 'creationTime' in result:
|
||||
result['creationTime'] = str(datetime.datetime.fromtimestamp(int(result['creationTime'])/1000))
|
||||
result['creationTime'] = utils.formatTimestampYMDHMSF(result['creationTime'])
|
||||
if 'domainAliases' in result:
|
||||
for i in range(0, len(result['domainAliases'])):
|
||||
if 'creationTime' in result['domainAliases'][i]:
|
||||
result['domainAliases'][i]['creationTime'] = str(datetime.datetime.fromtimestamp(int(result['domainAliases'][i]['creationTime'])/1000))
|
||||
result['domainAliases'][i]['creationTime'] = utils.formatTimestampYMDHMSF(result['domainAliases'][i]['creationTime'])
|
||||
print_json(None, result)
|
||||
|
||||
def doGetDomainAliasInfo():
|
||||
@@ -2065,7 +2071,7 @@ def doGetDomainAliasInfo():
|
||||
alias = sys.argv[3]
|
||||
result = callGAPI(cd.domainAliases(), 'get', customer=GC_Values[GC_CUSTOMER_ID], domainAliasName=alias)
|
||||
if 'creationTime' in result:
|
||||
result['creationTime'] = str(datetime.datetime.fromtimestamp(int(result['creationTime'])/1000))
|
||||
result['creationTime'] = utils.formatTimestampYMDHMSF(result['creationTime'])
|
||||
print_json(None, result)
|
||||
|
||||
def doGetCustomerInfo():
|
||||
@@ -2185,7 +2191,7 @@ def doPrintDomains(return_results=False):
|
||||
if attr in ['kind', 'etag', 'domainAliases', 'isPrimary']:
|
||||
continue
|
||||
if attr in ['creationTime',]:
|
||||
domain[attr] = str(datetime.datetime.fromtimestamp(int(domain[attr])/1000))
|
||||
domain[attr] = utils.formatTimestampYMDHMSF(domain[attr])
|
||||
if attr not in titles:
|
||||
titles.append(attr)
|
||||
domain_attributes[attr] = domain[attr]
|
||||
@@ -2200,7 +2206,7 @@ def doPrintDomains(return_results=False):
|
||||
if attr in ['kind', 'etag']:
|
||||
continue
|
||||
if attr in ['creationTime',]:
|
||||
aliasdomain[attr] = str(datetime.datetime.fromtimestamp(int(aliasdomain[attr])/1000))
|
||||
aliasdomain[attr] = utils.formatTimestampYMDHMSF(aliasdomain[attr])
|
||||
if attr not in titles:
|
||||
titles.append(attr)
|
||||
aliasdomain_attributes[attr] = aliasdomain[attr]
|
||||
@@ -2229,7 +2235,7 @@ def doPrintDomainAliases():
|
||||
if attr in ['kind', 'etag']:
|
||||
continue
|
||||
if attr == 'creationTime':
|
||||
domainAlias[attr] = str(datetime.datetime.fromtimestamp(int(domainAlias[attr])/1000))
|
||||
domainAlias[attr] = utils.formatTimestampYMDHMSF(domainAlias[attr])
|
||||
if attr not in titles:
|
||||
titles.append(attr)
|
||||
domainAlias_attributes[attr] = domainAlias[attr]
|
||||
@@ -3074,9 +3080,8 @@ def doPrintPrintJobs():
|
||||
jobCount = totalJobs
|
||||
break
|
||||
continue
|
||||
updateTime = int(job['updateTime'])/1000
|
||||
job['createTime'] = datetime.datetime.fromtimestamp(createTime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
job['updateTime'] = datetime.datetime.fromtimestamp(updateTime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
job['createTime'] = utils.formatTimestampYMDHMS(job['createTime'])
|
||||
job['updateTime'] = utils.formatTimestampYMDHMS(job['updateTime'])
|
||||
job['tags'] = ' '.join(job['tags'])
|
||||
addRowTitlesToCSVfile(flatten_json(job), csvRows, titles)
|
||||
if jobCount >= totalJobs:
|
||||
@@ -3116,12 +3121,9 @@ def doPrintPrinters():
|
||||
printers = callGAPI(cp.printers(), 'list', q=query, type=printer_type, connection_status=connection_status, extra_fields=extra_fields)
|
||||
checkCloudPrintResult(printers)
|
||||
for printer in printers['printers']:
|
||||
createTime = int(printer['createTime'])/1000
|
||||
accessTime = int(printer['accessTime'])/1000
|
||||
updateTime = int(printer['updateTime'])/1000
|
||||
printer['createTime'] = datetime.datetime.fromtimestamp(createTime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
printer['accessTime'] = datetime.datetime.fromtimestamp(accessTime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
printer['updateTime'] = datetime.datetime.fromtimestamp(updateTime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
printer['createTime'] = utils.formatTimestampYMDHMS(printer['createTime'])
|
||||
printer['accessTime'] = utils.formatTimestampYMDHMS(printer['accessTime'])
|
||||
printer['updateTime'] = utils.formatTimestampYMDHMS(printer['updateTime'])
|
||||
printer['tags'] = ' '.join(printer['tags'])
|
||||
addRowTitlesToCSVfile(flatten_json(printer), csvRows, titles)
|
||||
writeCSVfile(csvRows, titles, 'Printers', todrive)
|
||||
@@ -3544,12 +3546,9 @@ def doGetPrinterInfo():
|
||||
result = callGAPI(cp.printers(), 'get', printerid=printerid)
|
||||
checkCloudPrintResult(result)
|
||||
printer_info = result['printers'][0]
|
||||
createTime = int(printer_info['createTime'])/1000
|
||||
accessTime = int(printer_info['accessTime'])/1000
|
||||
updateTime = int(printer_info['updateTime'])/1000
|
||||
printer_info['createTime'] = datetime.datetime.fromtimestamp(createTime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
printer_info['accessTime'] = datetime.datetime.fromtimestamp(accessTime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
printer_info['updateTime'] = datetime.datetime.fromtimestamp(updateTime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
printer_info['createTime'] = utils.formatTimestampYMDHMS(printer_info['createTime'])
|
||||
printer_info['accessTime'] = utils.formatTimestampYMDHMS(printer_info['accessTime'])
|
||||
printer_info['updateTime'] = utils.formatTimestampYMDHMS(printer_info['updateTime'])
|
||||
printer_info['tags'] = ' '.join(printer_info['tags'])
|
||||
if not everything:
|
||||
del printer_info['capabilities']
|
||||
@@ -3705,16 +3704,38 @@ def formatACLRule(rule):
|
||||
return '(Scope: {0}:{1}, Role: {2})'.format(rule['scope']['type'], rule['scope']['value'], rule['role'])
|
||||
return '(Scope: {0}, Role: {1})'.format(rule['scope']['type'], rule['role'])
|
||||
|
||||
def doCalendarShowACL():
|
||||
def doCalendarPrintShowACLs(csvFormat):
|
||||
calendarId, cal = buildCalendarDataGAPIObject(sys.argv[2])
|
||||
if not cal:
|
||||
return
|
||||
acls = callGAPIpages(cal.acl(), 'list', 'items', calendarId=calendarId, fields='nextPageToken,items(role,scope)')
|
||||
toDrive = False
|
||||
i = 4
|
||||
while i < len(sys.argv):
|
||||
myarg = sys.argv[i].lower().replace('_', '')
|
||||
if csvFormat and myarg == 'todrive':
|
||||
toDrive = True
|
||||
i += 1
|
||||
else:
|
||||
systemErrorExit(2, '%s is not a valid argument for "gam calendar <email> %s"' % (sys.argv[i], ['showacl', 'printacl'][csvFormat]))
|
||||
acls = callGAPIpages(cal.acl(), 'list', 'items', calendarId=calendarId)
|
||||
i = 0
|
||||
count = len(acls)
|
||||
if csvFormat:
|
||||
titles = []
|
||||
rows = []
|
||||
else:
|
||||
count = len(acls)
|
||||
for rule in acls:
|
||||
i += 1
|
||||
print('Calendar: {0}, ACL: {1}{2}'.format(calendarId, formatACLRule(rule), currentCount(i, count)))
|
||||
if csvFormat:
|
||||
row = flatten_json(rule, None)
|
||||
for key in row:
|
||||
if key not in titles:
|
||||
titles.append(key)
|
||||
rows.append(row)
|
||||
else:
|
||||
print('Calendar: {0}, ACL: {1}{2}'.format(calendarId, formatACLRule(rule), currentCount(i, count)))
|
||||
if csvFormat:
|
||||
writeCSVfile(rows, titles, '%s Calendar ACLs' % calendarId, toDrive)
|
||||
|
||||
def _getCalendarACLScope(i, body):
|
||||
body['scope'] = {}
|
||||
@@ -3770,10 +3791,15 @@ def doCalendarDelACL():
|
||||
calendarId, cal = buildCalendarDataGAPIObject(sys.argv[2])
|
||||
if not cal:
|
||||
return
|
||||
body = {'role': 'none'}
|
||||
_getCalendarACLScope(5, body)
|
||||
print('Calendar: {0}, {1} ACL: {2}'.format(calendarId, 'Delete', formatACLScope(body)))
|
||||
callGAPI(cal.acl(), 'insert', calendarId=calendarId, body=body, sendNotifications=False)
|
||||
if sys.argv[4].lower() == 'id':
|
||||
ruleId = sys.argv[5]
|
||||
print('Removing rights for %s to %s' % (ruleId, calendarId))
|
||||
callGAPI(cal.acl(), 'delete', calendarId=calendarId, ruleId=ruleId)
|
||||
else:
|
||||
body = {'role': 'none'}
|
||||
_getCalendarACLScope(5, body)
|
||||
print('Calendar: {0}, {1} ACL: {2}'.format(calendarId, 'Delete', formatACLScope(body)))
|
||||
callGAPI(cal.acl(), 'insert', calendarId=calendarId, body=body, sendNotifications=False)
|
||||
|
||||
def doCalendarWipeData():
|
||||
calendarId, cal = buildCalendarDataGAPIObject(sys.argv[2])
|
||||
@@ -5318,6 +5344,34 @@ def transferDriveFiles(users):
|
||||
if not skipped_files:
|
||||
break
|
||||
|
||||
def sendOrDropEmail(users, method='send'):
|
||||
body = subject = ''
|
||||
recipient = None
|
||||
labels = None
|
||||
i = 4
|
||||
while i < len(sys.argv):
|
||||
myarg = sys.argv[i].lower().replace('_', '')
|
||||
if myarg == 'message':
|
||||
body = sys.argv[i+1]
|
||||
i += 2
|
||||
elif myarg == 'file':
|
||||
filename = sys.argv[i+1]
|
||||
i, encoding = getCharSet(i+2)
|
||||
body = readFile(filename, encoding=encoding)
|
||||
elif myarg == 'subject':
|
||||
subject = sys.argv[i+1]
|
||||
i += 2
|
||||
elif myarg == 'recipient':
|
||||
recipient = sys.argv[i+1]
|
||||
i += 2
|
||||
elif myarg == 'labels':
|
||||
labels = sys.argv[i+1].split(',')
|
||||
i += 2
|
||||
else:
|
||||
systemErrorExit(2, '%s is not a valid argument for "gam <users> sendemail"' % sys.argv[i])
|
||||
for user in users:
|
||||
send_email(subject, body, recipient, user, method, labels)
|
||||
|
||||
def doImap(users):
|
||||
enable = getBoolean(sys.argv[4], 'gam <users> imap')
|
||||
body = {'enabled': enable, 'autoExpunge': True, 'expungeBehavior': 'archive', 'maxFolderSize': 0}
|
||||
@@ -5764,7 +5818,7 @@ def printShowSmime(users, csvFormat):
|
||||
result = callGAPI(gmail.users().settings().sendAs().smimeInfo(), 'list', sendAsEmail=sendAsEmail, userId='me')
|
||||
smimes = result.get('smimeInfo', [])
|
||||
for j, _ in enumerate(smimes):
|
||||
smimes[j]['expiration'] = datetime.datetime.fromtimestamp(int(smimes[j]['expiration'])/1000).strftime('%Y-%m-%d %H:%M:%S')
|
||||
smimes[j]['expiration'] = utils.formatTimestampYMDHMS(smimes[j]['expiration'])
|
||||
if csvFormat:
|
||||
for smime in smimes:
|
||||
addRowTitlesToCSVfile(flatten_json(smime, flattened={'User': user}), csvRows, titles)
|
||||
@@ -6868,11 +6922,11 @@ def getVacation(users):
|
||||
print(' Contacts Only: {0}'.format(result['restrictToContacts']))
|
||||
print(' Domain Only: {0}'.format(result['restrictToDomain']))
|
||||
if 'startTime' in result:
|
||||
print(' Start Date: {0}'.format(datetime.datetime.fromtimestamp(int(result['startTime'])/1000).strftime('%Y-%m-%d')))
|
||||
print(' Start Date: {0}'.format(utils.formatTimestampYMD(result['startTime'])))
|
||||
else:
|
||||
print(' Start Date: Started')
|
||||
if 'endTime' in result:
|
||||
print(' End Date: {0}'.format(datetime.datetime.fromtimestamp(int(result['endTime'])/1000).strftime('%Y-%m-%d')))
|
||||
print(' End Date: {0}'.format(utils.formatTimestampYMD(result['endTime'])))
|
||||
else:
|
||||
print(' End Date: Not specified')
|
||||
print(utils.convertUTF8(' Subject: {0}'.format(result.get('responseSubject', 'None'))))
|
||||
@@ -7555,10 +7609,11 @@ def getCRMService(login_hint):
|
||||
discoveryServiceUrl=googleapiclient.discovery.V2_DISCOVERY_URI),
|
||||
http)
|
||||
|
||||
def getGAMProjectAPIs():
|
||||
def getGAMProjectFile(filepath):
|
||||
file_url = GAM_PROJECT_FILEPATH+filepath
|
||||
httpObj = _createHttpObj()
|
||||
_, c = httpObj.request(GAM_PROJECT_APIS, 'GET')
|
||||
return httpObj, c.decode(UTF8).splitlines()
|
||||
_, c = httpObj.request(file_url, 'GET')
|
||||
return c.decode(UTF8)
|
||||
|
||||
def enableGAMProjectAPIs(GAMProjectAPIs, httpObj, projectId, checkEnabled, i=0, count=0):
|
||||
apis = GAMProjectAPIs[:]
|
||||
@@ -7638,7 +7693,7 @@ def _createClientSecretsOauth2service(httpObj, projectId):
|
||||
print('Unknown error: %s' % content)
|
||||
return False
|
||||
|
||||
simplehttp, GAMProjectAPIs = getGAMProjectAPIs()
|
||||
GAMProjectAPIs = getGAMProjectFile('src/project-apis.txt').splitlines()
|
||||
enableGAMProjectAPIs(GAMProjectAPIs, httpObj, projectId, False)
|
||||
iam = googleapiclient.discovery.build('iam', 'v1',
|
||||
http=httpObj, cache_discovery=False,
|
||||
@@ -7683,6 +7738,7 @@ def _createClientSecretsOauth2service(httpObj, projectId):
|
||||
client_secret = input('Enter your Client Secret: ').strip()
|
||||
if not client_secret:
|
||||
client_secret = input().strip()
|
||||
simplehttp = _createHttpObj()
|
||||
client_valid = _checkClientAndSecret(simplehttp, client_id, client_secret)
|
||||
if client_valid:
|
||||
break
|
||||
@@ -7889,7 +7945,7 @@ def doUseProject():
|
||||
|
||||
def doUpdateProjects():
|
||||
_, httpObj, login_hint, projects, _ = _getLoginHintProjects(False)
|
||||
_, GAMProjectAPIs = getGAMProjectAPIs()
|
||||
GAMProjectAPIs = getGAMProjectFile('src/project-apis.txt').splitlines()
|
||||
count = len(projects)
|
||||
print('User: {0}, Update {1} Projects'.format(login_hint, count))
|
||||
i = 0
|
||||
@@ -10322,6 +10378,9 @@ def doGetMobileInfo():
|
||||
info = callGAPI(cd.mobiledevices(), 'get', customerId=GC_Values[GC_CUSTOMER_ID], resourceId=resourceId)
|
||||
if 'deviceId' in info:
|
||||
info['deviceId'] = info['deviceId'].encode('unicode-escape').decode(UTF8)
|
||||
attrib = 'securityPatchLevel'
|
||||
if attrib in info and int(info[attrib]):
|
||||
info[attrib] = utils.formatTimestampYMDHMS(info[attrib])
|
||||
print_json(None, info)
|
||||
|
||||
def print_json(object_name, object_value, spacing=''):
|
||||
@@ -10582,11 +10641,11 @@ def doGetASPs(users):
|
||||
if asp['creationTime'] == '0':
|
||||
created_date = 'Unknown'
|
||||
else:
|
||||
created_date = datetime.datetime.fromtimestamp(int(asp['creationTime'])/1000).strftime('%Y-%m-%d %H:%M:%S')
|
||||
created_date = utils.formatTimestampYMDHMS(asp['creationTime'])
|
||||
if asp['lastTimeUsed'] == '0':
|
||||
used_date = 'Never'
|
||||
else:
|
||||
used_date = datetime.datetime.fromtimestamp(int(asp['lastTimeUsed'])/1000).strftime('%Y-%m-%d %H:%M:%S')
|
||||
used_date = utils.formatTimestampYMDHMS(asp['lastTimeUsed'])
|
||||
print(' ID: %s\n Name: %s\n Created: %s\n Last Used: %s\n' % (asp['codeId'], asp['name'], created_date, used_date))
|
||||
else:
|
||||
print(' no ASPs for %s\n' % user)
|
||||
@@ -10869,17 +10928,33 @@ def doDeleteOrg():
|
||||
print("Deleting organization %s" % name)
|
||||
callGAPI(cd.orgunits(), 'delete', customerId=GC_Values[GC_CUSTOMER_ID], orgUnitPath=encodeOrgUnitPath(makeOrgUnitPathRelative(name)))
|
||||
|
||||
# Send an email
|
||||
def send_email(msg_subj, msg_txt, msg_rcpt=None):
|
||||
userId, gmail = buildGmailGAPIObject(_getValueFromOAuth('email'))
|
||||
if not msg_rcpt:
|
||||
msg_rcpt = userId
|
||||
msg = MIMEText(msg_txt)
|
||||
msg['Subject'] = msg_subj
|
||||
def send_email(subject, body, recipient=None, sender=None, method='send', labels=None):
|
||||
api_body = {}
|
||||
kwargs = {}
|
||||
if not sender:
|
||||
sender = _getValueFromOAuth('email')
|
||||
userId, gmail = buildGmailGAPIObject(sender)
|
||||
resource = gmail.users().messages()
|
||||
if labels and method in ['insert', 'import']:
|
||||
api_body['labelIds'] = labelsToLabelIds(gmail, labels)
|
||||
elif labels:
|
||||
systemErrorExit(3, 'labels argument is only valid for importemail and insertemail')
|
||||
if not recipient:
|
||||
recipient = userId
|
||||
msg = message_from_string(body)
|
||||
msg['Subject'] = subject
|
||||
msg['From'] = userId
|
||||
msg['To'] = msg_rcpt
|
||||
callGAPI(gmail.users().messages(), 'send',
|
||||
userId=userId, body={'raw': base64.urlsafe_b64encode(msg.as_bytes()).decode()})
|
||||
msg['To'] = recipient
|
||||
api_body['raw'] = base64.urlsafe_b64encode(msg.as_bytes()).decode()
|
||||
if method == 'draft':
|
||||
resource = gmail.users().drafts()
|
||||
method = 'create'
|
||||
api_body = {'message': api_body}
|
||||
elif method in ['insert', 'import']:
|
||||
kwargs['internalDateSource'] = 'dateHeader'
|
||||
if method == 'import':
|
||||
method = 'import_'
|
||||
callGAPI(resource, method, userId=userId, body=api_body, **kwargs)
|
||||
|
||||
def addFieldToFieldsList(fieldName, fieldsChoiceMap, fieldsList):
|
||||
fields = fieldsChoiceMap[fieldName.lower()]
|
||||
@@ -10943,7 +11018,7 @@ def sortCSVTitles(firstTitle, titles):
|
||||
|
||||
def writeCSVfile(csvRows, titles, list_type, todrive):
|
||||
def rowDateTimeFilterMatch(dateMode, rowDate, op, filterDate):
|
||||
if not rowDate:
|
||||
if not rowDate or not isinstance(rowDate, str):
|
||||
return False
|
||||
try:
|
||||
rowTime = dateutil.parser.parse(rowDate, ignoretz=True)
|
||||
@@ -10999,7 +11074,9 @@ def writeCSVfile(csvRows, titles, list_type, todrive):
|
||||
sys.stderr.write('WARNING: Row filter column "{0}" is not in output columns\n'.format(column))
|
||||
continue
|
||||
if filterVal[0] == 'regex':
|
||||
csvRows = [row for row in csvRows if filterVal[1].search(row.get(column, ''))]
|
||||
csvRows = [row for row in csvRows if filterVal[1].search(str(row.get(column, '')))]
|
||||
elif filterVal[0] == 'notregex':
|
||||
csvRows = [row for row in csvRows if not filterVal[1].search(str(row.get(column, '')))]
|
||||
elif filterVal[0] in ['date', 'time']:
|
||||
csvRows = [row for row in csvRows if rowDateTimeFilterMatch(filterVal[0] == 'date', row.get(column, ''), filterVal[1], filterVal[2])]
|
||||
elif filterVal[0] == 'count':
|
||||
@@ -12021,10 +12098,12 @@ def doPrintMobileDevices():
|
||||
else:
|
||||
if attrib not in titles:
|
||||
titles.append(attrib)
|
||||
if attrib != 'deviceId':
|
||||
row[attrib] = mobile[attrib]
|
||||
else:
|
||||
if attrib == 'deviceId':
|
||||
row[attrib] = mobile[attrib].encode('unicode-escape').decode(UTF8)
|
||||
elif attrib == 'securityPatchLevel' and int(mobile[attrib]):
|
||||
row[attrib] = utils.formatTimestampYMDHMS(mobile[attrib])
|
||||
else:
|
||||
row[attrib] = mobile[attrib]
|
||||
csvRows.append(row)
|
||||
sortCSVTitles(['resourceId', 'deviceId', 'serialNumber', 'name', 'email', 'status'], titles)
|
||||
writeCSVfile(csvRows, titles, 'Mobile', todrive)
|
||||
@@ -12139,12 +12218,14 @@ def _checkTPMVulnerability(cros):
|
||||
cros['tpmVersionInfo']['tpmVulnerability'] = 'NOT IMPACTED'
|
||||
|
||||
def _guessAUE(cros, guessedAUEs):
|
||||
if not GC_Values.get('CROS_AUE_DATES', None):
|
||||
GC_Values['CROS_AUE_DATES'] = json.loads(getGAMProjectFile('src/cros-aue-dates.json'))
|
||||
crosModel = cros.get('model')
|
||||
if crosModel:
|
||||
if crosModel not in guessedAUEs:
|
||||
closest_match = difflib.get_close_matches(crosModel.lower(), CROS_AUE_DATES, n=1)
|
||||
closest_match = difflib.get_close_matches(crosModel.lower(), GC_Values['CROS_AUE_DATES'], n=1)
|
||||
if closest_match:
|
||||
guessedAUEs[crosModel] = {'guessedAUEDate': CROS_AUE_DATES[closest_match[0]],
|
||||
guessedAUEs[crosModel] = {'guessedAUEDate': GC_Values['CROS_AUE_DATES'][closest_match[0]],
|
||||
'guessedAUEModel': closest_match[0]}
|
||||
else:
|
||||
guessedAUEs[crosModel] = {'guessedAUEDate': u'',
|
||||
@@ -14043,7 +14124,9 @@ def ProcessGAMCommand(args):
|
||||
elif command == 'calendar':
|
||||
argument = sys.argv[3].lower()
|
||||
if argument == 'showacl':
|
||||
doCalendarShowACL()
|
||||
doCalendarPrintShowACLs(False)
|
||||
elif argument == 'printacl':
|
||||
doCalendarPrintShowACLs(True)
|
||||
elif argument == 'add':
|
||||
doCalendarAddACL('Add')
|
||||
elif argument in ['del', 'delete']:
|
||||
@@ -14390,6 +14473,14 @@ def ProcessGAMCommand(args):
|
||||
elif command == 'imap':
|
||||
#doImap(users)
|
||||
runCmdForUsers(doImap, users, default_to_batch=True)
|
||||
elif command == 'sendemail':
|
||||
sendOrDropEmail(users, 'send')
|
||||
elif command == 'importemail':
|
||||
sendOrDropEmail(users, 'import')
|
||||
elif command == 'insertemail':
|
||||
sendOrDropEmail(users, 'insert')
|
||||
elif command == 'draftemail':
|
||||
sendOrDropEmail(users, 'draft')
|
||||
elif command == 'language':
|
||||
doLanguage(users)
|
||||
elif command in ['pop', 'pop3']:
|
||||
|
||||
@@ -3,6 +3,6 @@ dnspython
|
||||
google-api-python-client
|
||||
google-auth
|
||||
google-auth-httplib2
|
||||
google-auth-oauthlib
|
||||
google-auth-oauthlib==0.4.0
|
||||
httplib2>=0.13.0
|
||||
passlib
|
||||
|
||||
@@ -4,6 +4,8 @@ from xml.etree import ElementTree as ET
|
||||
import requests
|
||||
from html.parser import HTMLParser
|
||||
import string
|
||||
import sys
|
||||
import json
|
||||
import dateutil.parser
|
||||
|
||||
class MyHTMLParser(HTMLParser):
|
||||
@@ -27,18 +29,18 @@ class MyHTMLParser(HTMLParser):
|
||||
fullname = '%s %s' % (oem, model)
|
||||
fullname = fullname.lower()
|
||||
date = dateutil.parser.parse(data).replace(day=1).strftime('%Y-%m-%dT00:00:00.000Z')
|
||||
output_rows.append(" '%s': '%s'," % (fullname, date))
|
||||
output_rows[fullname] = date
|
||||
if fullname in exceptions:
|
||||
for value in exceptions[fullname]:
|
||||
output_rows.append(" '%s': '%s'," % (value, date))
|
||||
output_rows[value] = date
|
||||
data_is_date = False
|
||||
else:
|
||||
model = ''.join(filter(lambda x: x in printable, data)).replace('"', '\\"')
|
||||
model = ''.join(filter(lambda x: x in printable, data))
|
||||
data_is_date = True
|
||||
next_data_is_td = False
|
||||
|
||||
global oem, next_data_is_oem, next_data_is_td, data_is_date, model, printable, exceptions, output_rows
|
||||
output_rows = []
|
||||
output_rows = {}
|
||||
printable = set(string.printable)
|
||||
exceptions = {
|
||||
# 'AUE OEM MODEL': ['API MODEL 1', ...]
|
||||
@@ -95,10 +97,6 @@ next_data_is_oem = False
|
||||
next_data_is_td = False
|
||||
data_is_date = False
|
||||
auepage = requests.get('https://support.google.com/chrome/a/answer/6220366?hl=en')
|
||||
print('CROS_AUE_DATES = {')
|
||||
parser = MyHTMLParser()
|
||||
parser.feed(auepage.content.decode('utf-8'))
|
||||
output_rows.sort(key=str.lower)
|
||||
for row in output_rows:
|
||||
print(row)
|
||||
print('}')
|
||||
print(json.dumps(output_rows, indent=2, sort_keys=True))
|
||||
|
||||
14
src/utils.py
14
src/utils.py
@@ -1,3 +1,4 @@
|
||||
import datetime
|
||||
import re
|
||||
import sys
|
||||
from html.entities import name2codepoint
|
||||
@@ -22,8 +23,7 @@ class _DeHTMLParser(HTMLParser):
|
||||
self.__text.append(data)
|
||||
|
||||
def handle_charref(self, name):
|
||||
self.__text.append(
|
||||
chr(int(name[1:], 16)) if name.startswith('x') else chr(int(name)))
|
||||
self.__text.append(chr(int(name[1:], 16)) if name.startswith('x') else chr(int(name)))
|
||||
|
||||
def handle_entityref(self, name):
|
||||
cp = name2codepoint.get(name)
|
||||
@@ -73,6 +73,16 @@ def indentMultiLineText(message, n=0):
|
||||
return message.replace('\n', '\n{0}'.format(' ' * n)).rstrip()
|
||||
|
||||
|
||||
def formatTimestampYMD(timestamp):
|
||||
return datetime.datetime.fromtimestamp(int(timestamp)/1000).strftime('%Y-%m-%d')
|
||||
|
||||
def formatTimestampYMDHMS(timestamp):
|
||||
return datetime.datetime.fromtimestamp(int(timestamp)/1000).strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
def formatTimestampYMDHMSF(timestamp):
|
||||
return str(datetime.datetime.fromtimestamp(int(timestamp)/1000))
|
||||
|
||||
|
||||
def formatFileSize(fileSize):
|
||||
if fileSize == 0:
|
||||
return '0kb'
|
||||
|
||||
264
src/var.py
264
src/var.py
@@ -6,7 +6,7 @@ import platform
|
||||
import re
|
||||
|
||||
gam_author = 'Jay Lee <jay0lee@gmail.com>'
|
||||
gam_version = '4.86'
|
||||
gam_version = '4.88'
|
||||
gam_license = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
GAM_URL = 'https://git.io/gam'
|
||||
@@ -20,7 +20,7 @@ GAM_RELEASES = 'https://github.com/jay0lee/GAM/releases'
|
||||
GAM_WIKI = 'https://github.com/jay0lee/GAM/wiki'
|
||||
GAM_ALL_RELEASES = 'https://api.github.com/repos/jay0lee/GAM/releases'
|
||||
GAM_LATEST_RELEASE = GAM_ALL_RELEASES+'/latest'
|
||||
GAM_PROJECT_APIS = 'https://raw.githubusercontent.com/jay0lee/GAM/master/src/project-apis.txt'
|
||||
GAM_PROJECT_FILEPATH = 'https://raw.githubusercontent.com/jay0lee/GAM/master/'
|
||||
|
||||
true_values = ['on', 'yes', 'enabled', 'true', '1']
|
||||
false_values = ['off', 'no', 'disabled', 'false', '0']
|
||||
@@ -600,266 +600,6 @@ CROS_END_ARGUMENTS = ['end', 'enddate']
|
||||
CROS_TPM_VULN_VERSIONS = ['41f', '420', '628', '8520',]
|
||||
CROS_TPM_FIXED_VERSIONS = ['422', '62b', '8521',]
|
||||
|
||||
# parsed from https://support.google.com/chrome/a/answer/6220366?hl=en
|
||||
# using src/tools/parse-aue.py
|
||||
CROS_AUE_DATES = {
|
||||
'acer ac700': '2016-08-01T00:00:00.000Z',
|
||||
'acer c7 chromebook (c710)': '2017-10-01T00:00:00.000Z',
|
||||
'acer c7 chromebook': '2017-10-01T00:00:00.000Z',
|
||||
'acer c720 chromebook': '2019-06-01T00:00:00.000Z',
|
||||
'acer c740 chromebook': '2019-06-01T00:00:00.000Z',
|
||||
'acer chromebase 24': '2021-06-01T00:00:00.000Z',
|
||||
'acer chromebase': '2020-08-01T00:00:00.000Z',
|
||||
'acer chromebook 11 (c720, c720p)': '2019-06-01T00:00:00.000Z',
|
||||
'acer chromebook 11 (c732, c732t, c732l, c732lt)': '2023-11-01T00:00:00.000Z',
|
||||
'acer chromebook 11 (c740)': '2020-06-01T00:00:00.000Z',
|
||||
'acer chromebook 11 (c771, c771t)': '2022-11-01T00:00:00.000Z',
|
||||
'acer chromebook 11 (cb3-111, c730, c730e)': '2019-08-01T00:00:00.000Z',
|
||||
'acer chromebook 11 (cb3-131, c735)': '2021-01-01T00:00:00.000Z',
|
||||
'acer chromebook 11 (cb311-8h, cb311-8ht)': '2023-11-01T00:00:00.000Z',
|
||||
'acer chromebook 11 n7 (c731, c731t)': '2022-01-01T00:00:00.000Z',
|
||||
'acer chromebook 13 (cb5-311)': '2019-09-01T00:00:00.000Z',
|
||||
'acer chromebook 13 (cb713-1w)': '2024-06-01T00:00:00.000Z',
|
||||
'acer chromebook 13(cb5-311, c810)': '2019-09-01T00:00:00.000Z',
|
||||
'acer chromebook 14 (cb3-431)': '2021-06-01T00:00:00.000Z',
|
||||
'acer chromebook 14 for work (cp5-471)': '2022-11-01T00:00:00.000Z',
|
||||
'acer chromebook 15 (c910 / cb5-571)': '2020-06-01T00:00:00.000Z',
|
||||
'acer chromebook 15 (cb3-531)': '2020-06-01T00:00:00.000Z',
|
||||
'acer chromebook 15 (cb3-532)': '2021-08-01T00:00:00.000Z',
|
||||
'acer chromebook 15 (cb315-1h,cb315-1ht)': '2023-11-01T00:00:00.000Z',
|
||||
'acer chromebook 15 (cb5-571, c910)': '2020-06-01T00:00:00.000Z',
|
||||
'acer chromebook 15 (cb515-1h,cb515-1ht)': '2023-11-01T00:00:00.000Z',
|
||||
'acer chromebook 311 (c721, c733, c733u, c733t)': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook 311': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook 311': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook 315 (cb315-2h)': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook 315': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook 512 (c851, c851t)': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook 514': '2023-11-01T00:00:00.000Z',
|
||||
'acer chromebook 714 (cb714-1w / cb714-1wt)': '2024-06-01T00:00:00.000Z',
|
||||
'acer chromebook 715 (cb715-1w / cb715-1wt)': '2024-06-01T00:00:00.000Z',
|
||||
'acer chromebook r11 (cb5-132t, c738t)': '2021-06-01T00:00:00.000Z',
|
||||
'acer chromebook r13 (cb5-312t)': '2021-09-01T00:00:00.000Z',
|
||||
'acer chromebook spin 11 (cp311-h1, cp311-1hn)': '2023-11-01T00:00:00.000Z',
|
||||
'acer chromebook spin 11 (r751t)': '2023-11-01T00:00:00.000Z',
|
||||
'acer chromebook spin 13 (cp713-1wn)': '2024-06-01T00:00:00.000Z',
|
||||
'acer chromebook spin 15 (cp315)': '2023-11-01T00:00:00.000Z',
|
||||
'acer chromebook spin 311 (r721t)': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook spin 511 (r752t, r752tn)': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook spin 511': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook spin 512 (r851tn)': '2025-06-01T00:00:00.000Z',
|
||||
'acer chromebook tab 10': '2023-08-01T00:00:00.000Z',
|
||||
'acer chromebox cxi2 / cxv2': '2020-06-01T00:00:00.000Z',
|
||||
'acer chromebox cxi2': '2020-06-01T00:00:00.000Z',
|
||||
'acer chromebox cxi3': '2024-06-01T00:00:00.000Z',
|
||||
'acer chromebox': '2019-09-01T00:00:00.000Z',
|
||||
'aopen chromebase commercial': '2020-09-01T00:00:00.000Z',
|
||||
'aopen chromebase mini': '2022-02-01T00:00:00.000Z',
|
||||
'aopen chromebox commercial 2': '2024-06-01T00:00:00.000Z',
|
||||
'aopen chromebox commercial': '2020-09-01T00:00:00.000Z',
|
||||
'aopen chromebox mini': '2022-02-01T00:00:00.000Z',
|
||||
'asi chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'asus chromebit cs10': '2020-11-01T00:00:00.000Z',
|
||||
'asus chromebook c200': '2019-06-01T00:00:00.000Z',
|
||||
'asus chromebook c200ma': '2019-06-01T00:00:00.000Z',
|
||||
'asus chromebook c201pa': '2020-06-01T00:00:00.000Z',
|
||||
'asus chromebook c201pa': '2020-06-01T00:00:00.000Z',
|
||||
'asus chromebook c202sa': '2021-06-01T00:00:00.000Z',
|
||||
'asus chromebook c204': '2025-06-01T00:00:00.000Z',
|
||||
'asus chromebook c204': '2025-06-01T00:00:00.000Z',
|
||||
'asus chromebook c213na': '2023-11-01T00:00:00.000Z',
|
||||
'asus chromebook c223': '2023-11-01T00:00:00.000Z',
|
||||
'asus chromebook c300': '2019-08-01T00:00:00.000Z',
|
||||
'asus chromebook c300ma': '2019-08-01T00:00:00.000Z',
|
||||
'asus chromebook c300sa / c301sa': '2021-06-01T00:00:00.000Z',
|
||||
'asus chromebook c403': '2023-11-01T00:00:00.000Z',
|
||||
'asus chromebook c423': '2023-11-01T00:00:00.000Z',
|
||||
'asus chromebook c523': '2023-11-01T00:00:00.000Z',
|
||||
'asus chromebook flip c100pa': '2020-07-01T00:00:00.000Z',
|
||||
'asus chromebook flip c101pa': '2023-08-01T00:00:00.000Z',
|
||||
'asus chromebook flip c213': '2023-11-01T00:00:00.000Z',
|
||||
'asus chromebook flip c214': '2025-06-01T00:00:00.000Z',
|
||||
'asus chromebook flip c302': '2022-11-01T00:00:00.000Z',
|
||||
'asus chromebook flip c434': '2024-06-01T00:00:00.000Z',
|
||||
'asus chromebook tablet ct100': '2023-08-01T00:00:00.000Z',
|
||||
'asus chromebox (cn60)': '2019-09-01T00:00:00.000Z',
|
||||
'asus chromebox 2 (cn62)': '2021-06-01T00:00:00.000Z',
|
||||
'asus chromebox 3 (cn65)': '2024-06-01T00:00:00.000Z',
|
||||
'asus chromebox 3': '2024-06-01T00:00:00.000Z',
|
||||
'asus chromebox cn60': '2019-09-01T00:00:00.000Z',
|
||||
'asus chromebox cn62': '2021-06-01T00:00:00.000Z',
|
||||
'bobicus chromebook 11': '2020-06-01T00:00:00.000Z',
|
||||
'chromebook 11 (c730 / cb3-111)': '2019-08-01T00:00:00.000Z',
|
||||
'chromebook 11 (c735)': '2021-01-01T00:00:00.000Z',
|
||||
'chromebook 15 (cb515 - 1ht / 1h)': '2023-11-01T00:00:00.000Z',
|
||||
'chromebook 311 (c721)': '2025-06-01T00:00:00.000Z',
|
||||
'chromebook pcm-116e': '2020-06-01T00:00:00.000Z',
|
||||
'consumer chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'cr-48': '2015-12-01T00:00:00.000Z',
|
||||
'crambo chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'ctl chromebook j41 / j41t': '2023-11-01T00:00:00.000Z',
|
||||
'ctl chromebook nl7 / nl7t-360 / nl7tw-360': '2023-11-01T00:00:00.000Z',
|
||||
'ctl chromebook nl7': '2023-11-01T00:00:00.000Z',
|
||||
'ctl chromebook tab tx1': '2023-08-01T00:00:00.000Z',
|
||||
'ctl chromebook tablet tx1 for education': '2023-08-01T00:00:00.000Z',
|
||||
'ctl chromebox cbx1': '2024-06-01T00:00:00.000Z',
|
||||
'ctl j2 / j4 chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'ctl j5 chromebook': '2021-08-01T00:00:00.000Z',
|
||||
'ctl n6 education chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'ctl nl61 chromebook': '2021-08-01T00:00:00.000Z',
|
||||
'dell chromebook 11 (3120)': '2020-06-01T00:00:00.000Z',
|
||||
'dell chromebook 11 (3180)': '2022-05-01T00:00:00.000Z',
|
||||
'dell chromebook 11 (5190)': '2023-11-01T00:00:00.000Z',
|
||||
'dell chromebook 11 2-in-1 (3189)': '2022-05-01T00:00:00.000Z',
|
||||
'dell chromebook 11 2-in-1 (5190)': '2023-11-01T00:00:00.000Z',
|
||||
'dell chromebook 11': '2019-06-01T00:00:00.000Z',
|
||||
'dell chromebook 13 (3380)': '2022-11-01T00:00:00.000Z',
|
||||
'dell chromebook 13 (7310)': '2020-09-01T00:00:00.000Z',
|
||||
'dell chromebook 3100 2-in-1': '2025-06-01T00:00:00.000Z',
|
||||
'dell chromebook 3100': '2025-06-01T00:00:00.000Z',
|
||||
'dell chromebook 3400': '2025-06-01T00:00:00.000Z',
|
||||
'dell chromebox': '2019-09-01T00:00:00.000Z',
|
||||
'dell inspiron chromebook 14 2-in-1 (7486)': '2024-06-01T00:00:00.000Z',
|
||||
'edugear chromebook k': '2020-06-01T00:00:00.000Z',
|
||||
'edugear chromebook m': '2020-06-01T00:00:00.000Z',
|
||||
'edugear chromebook r': '2020-06-01T00:00:00.000Z',
|
||||
'edugear cmt chromebook': '2021-08-01T00:00:00.000Z',
|
||||
'edxis chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'edxis education chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'epik 11.6" chromebook elb1101': '2020-06-01T00:00:00.000Z',
|
||||
'google chromebook pixel (2015)': '2020-06-01T00:00:00.000Z',
|
||||
'google chromebook pixel': '2018-06-01T00:00:00.000Z',
|
||||
'google cr-48': '2015-12-01T00:00:00.000Z',
|
||||
'google pixel slate': '2024-06-01T00:00:00.000Z',
|
||||
'google pixelbook': '2024-06-01T00:00:00.000Z',
|
||||
'haier chromebook 11 c': '2021-08-01T00:00:00.000Z',
|
||||
'haier chromebook 11 g2': '2020-09-01T00:00:00.000Z',
|
||||
'haier chromebook 11': '2020-06-01T00:00:00.000Z',
|
||||
'haier chromebook 11e': '2020-06-01T00:00:00.000Z',
|
||||
'hexa chromebook pi': '2020-06-01T00:00:00.000Z',
|
||||
'hisense chromebook 11': '2020-06-01T00:00:00.000Z',
|
||||
'hp chromebook 11 1100-1199 / hp chromebook 11 g1': '2018-10-01T00:00:00.000Z',
|
||||
'hp chromebook 11 2000-2099 / hp chromebook 11 g2': '2019-06-01T00:00:00.000Z',
|
||||
'hp chromebook 11 2100-2199 / hp chromebook 11 g3': '2020-06-01T00:00:00.000Z',
|
||||
'hp chromebook 11 2200-2299 / hp chromebook 11 g4/g4 ee': '2020-06-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g1': '2018-10-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g2': '2019-06-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g3': '2020-06-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g4/g4 ee': '2020-06-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g5 / hp chromebook 11-vxxx': '2021-07-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g5 ee': '2022-01-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g5': '2021-07-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g6 ee': '2023-11-01T00:00:00.000Z',
|
||||
'hp chromebook 11 g7 ee': '2025-06-01T00:00:00.000Z',
|
||||
'hp chromebook 11a g6 ee': '2025-06-01T00:00:00.000Z',
|
||||
'hp chromebook 13 g1': '2022-11-01T00:00:00.000Z',
|
||||
'hp chromebook 14 / hp chromebook 14 g5': '2023-11-01T00:00:00.000Z',
|
||||
'hp chromebook 14 ak000-099 / hp chromebook 14 g4': '2021-09-01T00:00:00.000Z',
|
||||
'hp chromebook 14 db0000-db0999': '2025-06-01T00:00:00.000Z',
|
||||
'hp chromebook 14 g3': '2019-10-01T00:00:00.000Z',
|
||||
'hp chromebook 14 g4': '2021-09-01T00:00:00.000Z',
|
||||
'hp chromebook 14 g5': '2023-11-01T00:00:00.000Z',
|
||||
'hp chromebook 14 x000-x999 / hp chromebook 14 g3': '2019-10-01T00:00:00.000Z',
|
||||
'hp chromebook 14': '2019-06-01T00:00:00.000Z',
|
||||
'hp chromebook 14a g5': '2025-06-01T00:00:00.000Z',
|
||||
'hp chromebook 15 g1': '2024-06-01T00:00:00.000Z',
|
||||
'hp chromebook x2 ': '2024-06-01T00:00:00.000Z',
|
||||
'hp chromebook x360 11 g1 ee': '2023-11-01T00:00:00.000Z',
|
||||
'hp chromebook x360 11 g2 ee': '2025-06-01T00:00:00.000Z',
|
||||
'hp chromebook x360 14 g1': '2024-06-01T00:00:00.000Z',
|
||||
'hp chromebook x360 14': '2024-06-01T00:00:00.000Z',
|
||||
'hp chromebox cb1-(000-099) / hp chromebox g1/ hp chromebox for meetings': '2019-09-01T00:00:00.000Z',
|
||||
'hp chromebox g1': '2019-09-01T00:00:00.000Z',
|
||||
'hp chromebox g2': '2024-06-01T00:00:00.000Z',
|
||||
'hp pavilion chromebook 14': '2018-02-01T00:00:00.000Z',
|
||||
'jp sa couto chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'lava xolo chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'lenovo 100e chromebook 2nd gen mtk': '2025-06-01T00:00:00.000Z',
|
||||
'lenovo 100e chromebook 2nd gen': '2025-06-01T00:00:00.000Z',
|
||||
'lenovo 100e chromebook': '2023-11-01T00:00:00.000Z',
|
||||
'lenovo 100s chromebook': '2020-09-01T00:00:00.000Z',
|
||||
'lenovo 14e chromebook': '2025-06-01T00:00:00.000Z',
|
||||
'lenovo 300e chromebook 2nd gen mtk': '2025-06-01T00:00:00.000Z',
|
||||
'lenovo 300e chromebook 2nd gen': '2025-06-01T00:00:00.000Z',
|
||||
'lenovo 300e chromebook': '2025-06-01T00:00:00.000Z',
|
||||
'lenovo 500e chromebook 2nd gen': '2025-06-01T00:00:00.000Z',
|
||||
'lenovo 500e chromebook': '2023-11-01T00:00:00.000Z',
|
||||
'lenovo chromebook c330': '2022-06-01T00:00:00.000Z',
|
||||
'lenovo chromebook s330': '2022-06-01T00:00:00.000Z',
|
||||
'lenovo flex 11 chromebook': '2022-06-01T00:00:00.000Z',
|
||||
'lenovo ideapad c330 chromebook': '2022-06-01T00:00:00.000Z',
|
||||
'lenovo ideapad s330 chromebook': '2022-06-01T00:00:00.000Z',
|
||||
'lenovo n20 chromebook': '2019-06-01T00:00:00.000Z',
|
||||
'lenovo n21 chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'lenovo n22 chromebook': '2021-06-01T00:00:00.000Z',
|
||||
'lenovo n23 chromebook': '2021-06-01T00:00:00.000Z',
|
||||
'lenovo n23 yoga chromebook': '2022-06-01T00:00:00.000Z',
|
||||
'lenovo n42 chromebook': '2021-06-01T00:00:00.000Z',
|
||||
'lenovo thinkcentre chromebox': '2020-06-01T00:00:00.000Z',
|
||||
'lenovo thinkpad 11e 3rd gen chromebook': '2021-06-01T00:00:00.000Z',
|
||||
'lenovo thinkpad 11e 4th gen chromebook': '2023-11-01T00:00:00.000Z',
|
||||
'lenovo thinkpad 11e chromebook (4th gen)/lenovo thinkpad yoga 11e chromebook (4th gen)': '2023-11-01T00:00:00.000Z',
|
||||
'lenovo thinkpad 11e chromebook': '2019-06-01T00:00:00.000Z',
|
||||
'lenovo thinkpad 13': '2022-11-01T00:00:00.000Z',
|
||||
'lenovo thinkpad x131e chromebook': '2018-06-01T00:00:00.000Z',
|
||||
'lenovo yoga c630 chromebook': '2024-06-01T00:00:00.000Z',
|
||||
'lg chromebase (22cb25s)': '2020-06-01T00:00:00.000Z',
|
||||
'lg chromebase (22cv241)': '2019-06-01T00:00:00.000Z',
|
||||
'lumos education chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'm&a chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'mecer chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'mecer v2 chromebook': '2021-08-01T00:00:00.000Z',
|
||||
'medion chromebook akoya s2013 ': '2020-06-01T00:00:00.000Z',
|
||||
'medion chromebook s2015': '2020-06-01T00:00:00.000Z',
|
||||
'multilaser chromebook m11c': '2021-08-01T00:00:00.000Z',
|
||||
'ncomputing chromebook cx100': '2020-06-01T00:00:00.000Z',
|
||||
'ncomputing chromebook cx110': '2020-06-01T00:00:00.000Z',
|
||||
'nexian chromebook 11.6\"': '2020-06-01T00:00:00.000Z',
|
||||
'pcmerge chromebook al116': '2023-11-01T00:00:00.000Z',
|
||||
'pcmerge chromebookpcm-116e/pcm-116eb': '2020-06-01T00:00:00.000Z',
|
||||
'pcmerge chromebookpcm-116t-432b': '2021-08-01T00:00:00.000Z',
|
||||
'poin2 chromebook 11': '2020-06-01T00:00:00.000Z',
|
||||
'poin2 chromebook 11c': '2022-03-01T00:00:00.000Z',
|
||||
'poin2 chromebook 14': '2022-03-01T00:00:00.000Z',
|
||||
'positivo chromebook c216b': '2021-08-01T00:00:00.000Z',
|
||||
'positivo chromebook ch1190': '2020-06-01T00:00:00.000Z',
|
||||
'prowise 11.6" entry line chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'prowise chromebook eduline': '2023-11-01T00:00:00.000Z',
|
||||
'prowise chromebook entryline': '2020-06-01T00:00:00.000Z',
|
||||
'prowise chromebook proline': '2021-08-01T00:00:00.000Z',
|
||||
'prowise proline chromebook': '2021-08-01T00:00:00.000Z',
|
||||
'rgs education chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'samsung chromebook - xe303': '2018-07-01T00:00:00.000Z',
|
||||
'samsung chromebook 2 11\" - xe500c12': '2020-06-01T00:00:00.000Z',
|
||||
'samsung chromebook 2 11\"': '2019-06-01T00:00:00.000Z',
|
||||
'samsung chromebook 2 13\"': '2019-06-01T00:00:00.000Z',
|
||||
'samsung chromebook 3': '2021-06-01T00:00:00.000Z',
|
||||
'samsung chromebook plus (v2)': '2024-06-01T00:00:00.000Z',
|
||||
'samsung chromebook plus': '2023-08-01T00:00:00.000Z',
|
||||
'samsung chromebook pro': '2022-11-01T00:00:00.000Z',
|
||||
'samsung chromebook series 5 550': '2017-05-01T00:00:00.000Z',
|
||||
'samsung chromebook series 5': '2016-06-01T00:00:00.000Z',
|
||||
'samsung chromebook': '2018-07-01T00:00:00.000Z',
|
||||
'samsung chromebox series 3': '2018-03-01T00:00:00.000Z',
|
||||
'sector 5 e1 rugged chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'sector 5 e3 chromebook': '2023-11-01T00:00:00.000Z',
|
||||
'senkatel c1101 chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'thinkpad 11e chromebook 3rd gen (yoga/clamshell)': '2021-06-01T00:00:00.000Z',
|
||||
'thinkpad 13 chromebook': '2022-11-01T00:00:00.000Z',
|
||||
'toshiba chromebook 2 (2015 edition)': '2020-09-01T00:00:00.000Z',
|
||||
'toshiba chromebook 2': '2020-06-01T00:00:00.000Z',
|
||||
'toshiba chromebook': '2019-06-01T00:00:00.000Z',
|
||||
'true idc chromebook 11': '2020-06-01T00:00:00.000Z',
|
||||
'true idc chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'videonet chromebook bl10': '2020-06-01T00:00:00.000Z',
|
||||
'videonet chromebook': '2020-06-01T00:00:00.000Z',
|
||||
'viewsonic nmp660 chromebox': '2024-06-01T00:00:00.000Z',
|
||||
'viglen chromebook 11': '2020-06-01T00:00:00.000Z',
|
||||
'viglen chromebook 11c': '2023-11-01T00:00:00.000Z',
|
||||
'viglen chromebook 360': '2021-08-01T00:00:00.000Z',
|
||||
'xolo chromebook': '2020-06-01T00:00:00.000Z',
|
||||
}
|
||||
|
||||
COLLABORATIVE_ACL_CHOICES = {
|
||||
'members': 'ALL_MEMBERS',
|
||||
'managersonly': 'MANAGERS_ONLY',
|
||||
|
||||
Reference in New Issue
Block a user