Compare commits

...

26 Commits

Author SHA1 Message Date
Jay Lee
7ece7a0a1a 3.7.8, fix yubikey optional for pip package 2025-02-08 19:43:17 +00:00
Ross Scroggs
8d9f5689f3 Updated gam create vaultexport to include corpus gemini. 2025-02-08 09:38:37 -08:00
Ross Scroggs
8cd378ff8f Added option rawfields <BrowserFieldNameList> to gam info|print|show browsers
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-07 14:09:24 -08:00
Jay Lee
c0e037dda5 GAM 7.03.06 2025-02-07 21:11:01 +00:00
Jay Lee
b5730aadce gam print browsers rawfields. Starts #1746
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-07 14:49:46 +00:00
Jay Lee
4ec58bb844 actions: first attempt at auto publishing to PyPi
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-07 01:13:57 +00:00
Jay Lee
3ba99582dc GAM 7.03.05
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-06 22:24:30 +00:00
Jay Lee
b61a4f5115 [no ci] pypi: add gam a command 2025-02-06 17:22:07 -05:00
Jay Lee
7ce83b4623 fix YK as optional feature 2025-02-06 21:44:36 +00:00
Jay Lee
a58a998b49 make YK optional, 'pip install gam7[yubikey]' 2025-02-06 21:40:46 +00:00
Jay Lee
4e04bd7c51 Update pyproject.toml 2025-02-06 15:57:33 -05:00
Jay Lee
779ac0a6a0 Update pyproject.toml 2025-02-06 15:49:48 -05:00
Jay Lee
f18b7258bb Update pyproject.toml 2025-02-06 14:32:34 -05:00
Jay Lee
d4932c9d39 fix pyproject.toml license 2025-02-06 14:27:49 -05:00
Jay Lee
352845e482 pypi: initial package attempt for pip 2025-02-06 14:25:16 -05:00
Jay Lee
ff49c67580 Update build.yml
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-05 12:25:19 -05:00
Jay Lee
efee86cd33 actions: scratch build
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-05 08:41:46 -05:00
Ross Scroggs
a42eebdae1 Added option security to gam create cigroup
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-04 14:18:46 -08:00
Jay Lee
05333d9521 rebuild for Python 3.13.2
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-04 16:11:30 -05:00
Jay Lee
b04ba4b618 create cigroup now supports security label
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-03 15:55:59 +00:00
Ross Scroggs
c8108dace0 Fixed bug in gam update resoldcustomer #1743
Some checks failed
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
Check for Google Root CA Updates / check-apis (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-02 08:49:24 -08:00
Ross Scroggs
83a70d656e Updated gam <UserTypeEntity> show labels nested to properly display label nesting when labels have embedded / characters in their names.
Some checks are pending
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
2025-02-01 12:38:15 -08:00
Ross Scroggs
3a38609fbb Updated gam <UserTypeEntity> show labels nested to properly display label nesting when labels have embedded / characters in their names. 2025-02-01 12:34:27 -08:00
Ross Scroggs
e744aa29e3 Fix gam-install.sh #1741
Some checks failed
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2025-01-30 19:09:20 -08:00
Ross Scroggs
367c23a13c Updated gam create project to retry the following unexpected error:
Some checks failed
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
ERROR: 400 - invalidArgument - Service account gam-project-a1b2c@gam-project-a1b2c.iam.gserviceaccount.com does not exist.
2025-01-27 08:16:37 -08:00
Ross Scroggs
82e8977003 Updated gam create|use project to discontinue use of the Identity-Aware Proxy (IAP) OAuth Admin APIs
Some checks failed
Build and test GAM / build (Win64, build, 10, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, ubuntu-24.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, ubuntu-22.04-arm) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, linux-aarch64, ubuntu-22.04-arm, yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 8, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (aarch64, build, 9, darwin64-arm64, macos-15) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 7, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 13, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
Check for Google Root CA Updates / check-apis (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-26 15:30:45 -08:00
11 changed files with 376 additions and 110 deletions

View File

@@ -17,7 +17,7 @@ defaults:
working-directory: src working-directory: src
env: env:
SCRATCH_COUNTER: 7 SCRATCH_COUNTER: 9
OPENSSL_CONFIG_OPTS: no-fips --api=3.0.0 OPENSSL_CONFIG_OPTS: no-fips --api=3.0.0
OPENSSL_INSTALL_PATH: ${{ github.workspace }}/bin/ssl OPENSSL_INSTALL_PATH: ${{ github.workspace }}/bin/ssl
OPENSSL_SOURCE_PATH: ${{ github.workspace }}/src/openssl OPENSSL_SOURCE_PATH: ${{ github.workspace }}/src/openssl
@@ -129,7 +129,7 @@ jobs:
with: with:
path: | path: |
cache.tar.xz cache.tar.xz
key: gam-${{ matrix.jid }}-20250116 key: gam-${{ matrix.jid }}-20250204
- name: Untar Cache archive - name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true' if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'

32
.github/workflows/pypi.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: build and publish releases to PyPi
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
jobs:
pypi:
name: Upload release to PyPI
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/gam7
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0
- name: Install required packages to publish
run: |
python3 -m pip install --upgrade build
- name: Build packages
run: |
python -m build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1

64
pyproject.toml Normal file
View File

@@ -0,0 +1,64 @@
[project]
name = "gam7"
dynamic = [
"version",
]
authors = [
{ name="Jay Lee", email="jay0lee@gmail.com" },
{ name="Ross Scroggs", email="Ross.Scroggs@gmail.com" },
]
dependencies = [
"chardet",
"cryptography",
"distro; sys_platform=='linux'",
"filelock",
"google-api-python-client>=2.1",
"google-auth-httplib2",
"google-auth-oauthlib>=0.4.1",
"google-auth>=2.3.2",
"httplib2>=0.17.0",
"lxml",
"passlib>=1.7.2",
"pathvalidate",
"python-dateutil",
]
description = "CLI tool to manage Google Workspace"
readme = "README.md"
requires-python = ">=3.9"
classifiers = [
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Operating System :: OS Independent",
"License :: OSI Approved :: Apache License",
]
license = {text = "Apache License (2.0)"}
license-files = ["LICEN[CS]E*"]
[project.optional-dependencies]
yubikey = ["yubikey-manager>=5.0"]
[project.scripts]
gam = "gam.__main__:main"
[project.urls]
Homepage = "https://github.com/GAM-team/GAM"
Issues = "https://github.com/GAM-team/GAM/issues"
Discussion = "https://groups.google.com/group/google-apps-manager"
Chat = "https://git.io/gam-chat"
[tool.hatch.version]
path = "src/gam/__init__.py"
[tool.hatch.build.targets.wheel]
packages = ["src/gam"]
[build-system]
requires = [
"hatchling",
]
build-backend = "hatchling.build"

View File

@@ -1362,6 +1362,7 @@ gam create project [admin <EmailAddress>] [project <ProjectID>]
nokey] nokey]
gam use project [<EmailAddress>] [<ProjectID>] gam use project [<EmailAddress>] [<ProjectID>]
gam use project [admin <EmailAddress>] [project <ProjectID>] gam use project [admin <EmailAddress>] [project <ProjectID>]
[appname <String>] [supportemail <EmailAddress>]
[saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>] [saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>]
[sadescription <ServiceAccountDescription>] [sadescription <ServiceAccountDescription>]
[(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)| [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|
@@ -2089,19 +2090,25 @@ gam move browsers ou|org|orgunit <OrgUnitPath>
[batchsize <Integer>] [batchsize <Integer>]
gam info browser <DeviceID> gam info browser <DeviceID>
[basic|full|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>] (basic|full|annotated |
(<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
(rawfields "<BrowserFieldNameList>"))
[formatjson] [formatjson]
gam show browsers gam show browsers
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>)) ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
[querytime<String> <Time>] [querytime<String> <Time>]
[orderby <BrowserOrderByFieldName> [ascending|descending]] [orderby <BrowserOrderByFieldName> [ascending|descending]]
[basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>] (basic|full|annotated |
(<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
(rawfields "<BrowserFieldNameList>"))
[formatjson] [formatjson]
gam print browsers [todrive <ToDriveAttribute>*] gam print browsers [todrive <ToDriveAttribute>*]
([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>)) ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser>)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
[querytime<String> <Time>] [querytime<String> <Time>]
[orderby <BrowserOrderByFieldName> [ascending|descending]] [orderby <BrowserOrderByFieldName> [ascending|descending]]
[basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>] (basic|full|annotated |
(<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
(rawfields "<BrowserFieldNameList>"))
[sortheaders] [sortheaders]
[formatjson [quotechar <Character>]] [formatjson [quotechar <Character>]]
@@ -3926,8 +3933,11 @@ gam print group-members [todrive <ToDriveAttribute>*]
updatetime updatetime
<CIGroupFieldNameList> ::= "<CIGroupFieldName>(,<CIGroupFieldName>)*" <CIGroupFieldNameList> ::= "<CIGroupFieldName>(,<CIGroupFieldName>)*"
gam create cigroup <EmailAddress> [copyfrom <GroupItem>] <GroupAttribute>* gam create cigroup <EmailAddress>
[makeowner] [alias|aliases <CIGroupAliasList>] [dynamic <QueryDynamicGroup>] [copyfrom <GroupItem>] <GroupAttribute>*
[makeowner] [alias|aliases <CIGroupAliasList>]
[security|makesecuritygroup]
[dynamic <QueryDynamicGroup>]
gam update cigroup <GroupEntity> [copyfrom <GroupItem>] <GroupAttribute> gam update cigroup <GroupEntity> [copyfrom <GroupItem>] <GroupAttribute>
[security|makesecuritygroup| [security|makesecuritygroup|
dynamicsecurity|makedynamicsecuritygroup| dynamicsecurity|makedynamicsecuritygroup|
@@ -4514,7 +4524,7 @@ gam report users|user [todrive <ToDriveAttribute>*]
(country|countrycode <String>) (country|countrycode <String>)
gam create|add resoldcustomer <CustomerDomain> (customer_auth_token <String>) <ResoldCustomerAttribute>+ gam create|add resoldcustomer <CustomerDomain> (customer_auth_token <String>) <ResoldCustomerAttribute>+
gam update resoldcustomer <CustomerID> [customer_auth_token <String>] <ResoldCustomerAttribues>+ gam update resoldcustomer <CustomerID> <ResoldCustomerAttribues>+
gam info resoldcustomer <CustomerID> [formatjson] gam info resoldcustomer <CustomerID> [formatjson]
gam create|add resoldsubscription <CustomerID> (sku <SKUID>) gam create|add resoldsubscription <CustomerID> (sku <SKUID>)
@@ -5260,7 +5270,7 @@ gam print vaultcounts [todrive <ToDriveAttributes>*]
gam print vaultcounts [todrive <ToDriveAttributes>*] gam print vaultcounts [todrive <ToDriveAttributes>*]
matter <MatterItem> operation <String> [wait <Integer>] matter <MatterItem> operation <String> [wait <Integer>]
gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>) | (sitesurl <URLList>) (shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>) | (sitesurl <URLList>)
[scope all_data|held_data|unprocessed_data] [scope all_data|held_data|unprocessed_data]
@@ -5268,10 +5278,12 @@ gam create vaultexport|export matter <MatterItem> [name <String>] corpus calenda
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>] [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>] [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
[includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>] [includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
[driveclientsideencryption any|encrypted|unencrypted]
[includerooms <Boolean>] [includerooms <Boolean>]
[excludedrafts <Boolean>] [format mbox|pst] [excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>] [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
[covereddata calllogs|textmessages|voicemails] [covereddata calllogs|textmessages|voicemails]
[format ics|mbox|pst|xml]
[region any|europe|us] [showdetails|returnidonly] [region any|europe|us] [showdetails|returnidonly]
gam delete vaultexport|export <ExportItem> matter <MatterItem> gam delete vaultexport|export <ExportItem> matter <MatterItem>
gam delete vaultexport|export <MatterItem> <ExportItem> gam delete vaultexport|export <MatterItem> <ExportItem>
@@ -6575,6 +6587,8 @@ gam <UserTypeEntity> copy drivefile <DriveFileEntity>
[copysubfolderpermissions [<Boolean>]] [copysubfolderpermissions [<Boolean>]]
[copysubfolderinheritedpermissions [<Boolean>]] [copysubfolderinheritedpermissions [<Boolean>]]
[copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders] [copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders]
[copypermissionroles <DriveFileACLRoleList>]
[copypermissiontypes <DriveFileACLTypeList>]
[excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>] [excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
(mappermissionsdomain <DomainName> <DomainName>)* (mappermissionsdomain <DomainName> <DomainName>)*
[copysheetprotectedranges [<Boolean>]] [copysheetprotectedranges [<Boolean>]]

View File

@@ -1,3 +1,56 @@
7.03.07
Updated `gam create vaultexport` to include `corpus gemini`.
* See: https://workspaceupdates.googleblog.com/2025/02/google-vault-now-supports-gemini.html
7.03.06
Added option `rawfields "<BrowserFieldNameList>"` to `gam info|print|show browsers` that allows
specification of complex field lists with selected subfields.
* See: https://github.com/GAM-team/GAM/wiki/Chrome-Browser-Cloud-Management#raw-fields
7.03.05
Make GAM pip-installable: "pip install gam7"
7.03.04
Added option `security` to `gam create cigroup` that allows creation of a security group
in a single command.
Updated to Python 3.13.2.
7.03.03
Fixed bug in `gam update resoldcustomer` that caused the following error:
```
ERROR: Got an unexpected keyword argument customerAuthToken
```
7.03.02
Updated `gam <UserTypeEntity> show labels nested` to properly display label nesting
when labels have embedded `/` characters in their names.
7.03.01
Updated `gam create project` to retry the following unexpected error:
```
ERROR: 400 - invalidArgument - Service account gam-project-a1b2c@gam-project-a1b2c.iam.gserviceaccount.com does not exist.
```
7.03.00
Updated `gam create|use project` to discontinue use of the `Identity-Aware Proxy (IAP) OAuth Admin APIs`
that are being deprecated by Google. You will see a set of instructions detailing how to
configure the Oauth Consent screen and create the Oauth client.
Added options `copypermissionroles <DriveFileACLRoleList>` and `copypermissiontypes <DriveFileACLTypeList>`
to `gam <UserTypeEntity> copy drivefile` that provide more control over what permissions are copied
from the source files/folders to the destination files/folders.
7.02.11 7.02.11
Updated `gam report <ActivityApplicationName>` to display `id:<actor.profileId>` in the `emailAddress` column Updated `gam report <ActivityApplicationName>` to display `id:<actor.profileId>` in the `emailAddress` column

View File

@@ -112,6 +112,12 @@ else
check_type="authenticated" check_type="authenticated"
curl_opts=( "$GHCLIENT" ) curl_opts=( "$GHCLIENT" )
fi fi
curl_ver=$(curl --version|head -1|cut -d " " -f 2)
if [[ "${curl_ver:0:4}" < "7.76" ]]; then
curl_fail=( )
else
curl_fail=( "--fail-with-body" )
fi
echo_yellow "Checking GitHub URL $release_url for $gamversion GAM release ($check_type)..." echo_yellow "Checking GitHub URL $release_url for $gamversion GAM release ($check_type)..."
release_json=$(curl \ release_json=$(curl \
--silent \ --silent \
@@ -119,7 +125,7 @@ release_json=$(curl \
-H "Accept: application/vnd.github+json" \ -H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \ -H "X-GitHub-Api-Version: 2022-11-28" \
"$release_url" \ "$release_url" \
--fail-with-body) "${curl_fail[@]}")
curl_exit_code=$? curl_exit_code=$?
if [ $curl_exit_code -ne 0 ]; then if [ $curl_exit_code -ne 0 ]; then
echo_red "ERROR retrieving URL: ${release_json}" echo_red "ERROR retrieving URL: ${release_json}"

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
""" """
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>' __author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.02.11' __version__ = '7.03.08'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)' __license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
#pylint: disable=wrong-import-position #pylint: disable=wrong-import-position
@@ -4727,7 +4727,7 @@ def clearServiceCache(service):
DISCOVERY_URIS = [googleapiclient.discovery.V1_DISCOVERY_URI, googleapiclient.discovery.V2_DISCOVERY_URI] DISCOVERY_URIS = [googleapiclient.discovery.V1_DISCOVERY_URI, googleapiclient.discovery.V2_DISCOVERY_URI]
# Used for API.CLOUDRESOURCEMANAGER, API.SERVICEUSAGE, API.IAM, API.IAP # Used for API.CLOUDRESOURCEMANAGER, API.SERVICEUSAGE, API.IAM
def getAPIService(api, httpObj): def getAPIService(api, httpObj):
api, version, v2discovery = API.getVersion(api) api, version, v2discovery = API.getVersion(api)
return googleapiclient.discovery.build(api, version, http=httpObj, cache_discovery=False, return googleapiclient.discovery.build(api, version, http=httpObj, cache_discovery=False,
@@ -7356,6 +7356,12 @@ def addFieldToFieldsList(fieldName, fieldsChoiceMap, fieldsList):
def _getFieldsList(): def _getFieldsList():
return getString(Cmd.OB_FIELD_NAME_LIST).lower().replace('_', '').replace(',', ' ').split() return getString(Cmd.OB_FIELD_NAME_LIST).lower().replace('_', '').replace(',', ' ').split()
def _getRawFields(requiredField=None):
rawFields = getString(Cmd.OB_FIELDS)
if requiredField is None or requiredField in rawFields:
return rawFields
return f'{requiredField},{rawFields}'
def _addInitialField(fieldsList, initialField): def _addInitialField(fieldsList, initialField):
if isinstance(initialField, list): if isinstance(initialField, list):
fieldsList.extend(initialField) fieldsList.extend(initialField)
@@ -11361,13 +11367,32 @@ def doEnableAPIs():
url = f'https://console.cloud.google.com/apis/enableflow?apiid={apiid}&project={projectId}' url = f'https://console.cloud.google.com/apis/enableflow?apiid={apiid}&project={projectId}'
writeStdout(f' {url}\n\n') writeStdout(f' {url}\n\n')
def _waitForSvcAcctCompletion(i):
sleep_time = i*5
if i > 3:
sys.stdout.write(Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SVCACCT), sleep_time))
time.sleep(sleep_time)
def _grantRotateRights(iam, projectId, service_account, email, account_type='serviceAccount'): def _grantRotateRights(iam, projectId, service_account, email, account_type='serviceAccount'):
printEntityMessage([Ent.PROJECT, projectId, Ent.SVCACCT, email],
Msg.HAS_RIGHTS_TO_ROTATE_OWN_PRIVATE_KEY.format(email, service_account))
body = {'policy': {'bindings': [{'role': 'roles/iam.serviceAccountKeyAdmin', body = {'policy': {'bindings': [{'role': 'roles/iam.serviceAccountKeyAdmin',
'members': [f'{account_type}:{email}']}]}} 'members': [f'{account_type}:{email}']}]}}
callGAPI(iam.projects().serviceAccounts(), 'setIamPolicy', maxRetries = 10
resource=f'projects/{projectId}/serviceAccounts/{service_account}', body=body) printEntityMessage([Ent.PROJECT, projectId, Ent.SVCACCT, email],
Msg.HAS_RIGHTS_TO_ROTATE_OWN_PRIVATE_KEY.format(email, service_account))
for retry in range(1, maxRetries+1):
try:
callGAPI(iam.projects().serviceAccounts(), 'setIamPolicy',
throwReasons=[GAPI.INVALID_ARGUMENT],
resource=f'projects/{projectId}/serviceAccounts/{service_account}', body=body)
return True
except GAPI.invalidArgument as e:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, service_account], str(e))
if 'does not exist' not in str(e) or retry == maxRetries:
return False
_waitForSvcAcctCompletion(retry)
except Exception as e:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, service_account], str(e))
return False
def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True): def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True):
iam = getAPIService(API.IAM, httpObj) iam = getAPIService(API.IAM, httpObj)
@@ -11392,24 +11417,12 @@ def _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key=True)
clientId=service_account['uniqueId']): clientId=service_account['uniqueId']):
return False return False
sa_email = service_account['name'].rsplit('/', 1)[-1] sa_email = service_account['name'].rsplit('/', 1)[-1]
_grantRotateRights(iam, projectInfo['projectId'], sa_email, sa_email) return _grantRotateRights(iam, projectInfo['projectId'], sa_email, sa_email)
return True
def setGAMProjectConsentScreen(httpObj, projectId, appInfo):
sys.stdout.write(Msg.SETTING_GAM_PROJECT_CONSENT_SCREEN)
iap = getAPIService(API.IAP, httpObj)
try:
callGAPI(iap.projects().brands(), 'create',
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.INVALID_ARGUMENT],
parent=f'projects/{projectId}', body=appInfo)
except (GAPI.invalidArgument, GAPI.alreadyExists):
pass
def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key=True): def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key=True):
def _checkClientAndSecret(csHttpObj, client_id, client_secret): def _checkClientAndSecret(csHttpObj, client_id, client_secret):
post_data = {'client_id': client_id, 'client_secret': client_secret, post_data = {'client_id': client_id, 'client_secret': client_secret,
'code': 'ThisIsAnInvalidCodeOnlyBeingUsedToTestIfClientAndSecretAreValid', 'code': 'ThisIsAnInvalidCodeOnlyBeingUsedToTestIfClientAndSecretAreValid',
# 'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob', 'grant_type': 'authorization_code'}
'redirect_uri': 'http://127.0.0.1:8080', 'grant_type': 'authorization_code'} 'redirect_uri': 'http://127.0.0.1:8080', 'grant_type': 'authorization_code'}
_, content = csHttpObj.request(API.GOOGLE_OAUTH2_TOKEN_ENDPOINT, 'POST', urlencode(post_data), _, content = csHttpObj.request(API.GOOGLE_OAUTH2_TOKEN_ENDPOINT, 'POST', urlencode(post_data),
headers={'Content-type': 'application/x-www-form-urlencoded'}) headers={'Content-type': 'application/x-www-form-urlencoded'})
@@ -11434,16 +11447,14 @@ def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo,
if not enableGAMProjectAPIs(httpObj, projectInfo['projectId'], login_hint, False): if not enableGAMProjectAPIs(httpObj, projectInfo['projectId'], login_hint, False):
return return
if appInfo: sys.stdout.write(Msg.SETTING_GAM_PROJECT_CONSENT_SCREEN_CREATING_CLIENT)
setGAMProjectConsentScreen(httpObj, projectInfo['projectId'], appInfo) console_url = f'https://console.cloud.google.com/auth/clients?project={projectInfo["projectId"]}&authuser={login_hint}'
console_url = f'https://console.cloud.google.com/apis/credentials/oauthclient?project={projectInfo["projectId"]}&authuser={login_hint}'
csHttpObj = getHttpObj() csHttpObj = getHttpObj()
while True: while True:
sys.stdout.write(Msg.CREATE_PROJECT_INSTRUCTIONS.format(console_url)) sys.stdout.write(Msg.CREATE_CLIENT_INSTRUCTIONS.format(console_url, appInfo['applicationTitle'], appInfo['supportEmail']))
client_id = readStdin(Msg.ENTER_YOUR_CLIENT_ID).strip() client_id = readStdin(Msg.ENTER_YOUR_CLIENT_ID).strip()
if not client_id: if not client_id:
client_id = readStdin('').strip() client_id = readStdin('').strip()
sys.stdout.write(Msg.GO_BACK_TO_YOUR_BROWSER_AND_COPY_YOUR_CLIENT_SECRET_VALUE)
client_secret = readStdin(Msg.ENTER_YOUR_CLIENT_SECRET).strip() client_secret = readStdin(Msg.ENTER_YOUR_CLIENT_SECRET).strip()
if not client_secret: if not client_secret:
client_secret = readStdin('').strip() client_secret = readStdin('').strip()
@@ -11451,7 +11462,6 @@ def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo,
if client_valid: if client_valid:
break break
sys.stdout.write('\n') sys.stdout.write('\n')
# Deleted: "redirect_uris": ["http://localhost", "urn:ietf:wg:oauth:2.0:oob"],
cs_data = f'''{{ cs_data = f'''{{
"installed": {{ "installed": {{
"auth_provider_x509_cert_url": "{API.GOOGLE_AUTH_PROVIDER_X509_CERT_URL}", "auth_provider_x509_cert_url": "{API.GOOGLE_AUTH_PROVIDER_X509_CERT_URL}",
@@ -11464,7 +11474,6 @@ def _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo,
}} }}
}}''' }}'''
writeFile(GC.Values[GC.CLIENT_SECRETS_JSON], cs_data, continueOnError=False) writeFile(GC.Values[GC.CLIENT_SECRETS_JSON], cs_data, continueOnError=False)
sys.stdout.write(Msg.GO_BACK_TO_YOUR_BROWSER_AND_CLICK_OK_TO_CLOSE_THE_OAUTH_CLIENT_POPUP)
sys.stdout.write(Msg.TRUST_GAM_CLIENT_ID.format(GAM, client_id)) sys.stdout.write(Msg.TRUST_GAM_CLIENT_ID.format(GAM, client_id))
readStdin('') readStdin('')
if not _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key): if not _createOauth2serviceJSON(httpObj, projectInfo, svcAcctInfo, create_key):
@@ -11590,7 +11599,7 @@ def _getLoginHintProjectInfo(createCmd):
_checkProjectName(projectInfo['name']) _checkProjectName(projectInfo['name'])
elif _getSvcAcctInfo(myarg, svcAcctInfo): elif _getSvcAcctInfo(myarg, svcAcctInfo):
pass pass
elif createCmd and _getAppInfo(myarg, appInfo): elif _getAppInfo(myarg, appInfo):
pass pass
elif myarg in {'algorithm', 'localkeysize', 'validityhours', 'yubikey'}: elif myarg in {'algorithm', 'localkeysize', 'validityhours', 'yubikey'}:
Cmd.Backup() Cmd.Backup()
@@ -11874,14 +11883,15 @@ def doCreateProject():
# gam use project [<EmailAddress>] [<ProjectID>] # gam use project [<EmailAddress>] [<ProjectID>]
# gam use project [admin <EmailAddress>] [project <ProjectID>] # gam use project [admin <EmailAddress>] [project <ProjectID>]
# [appname <String>] [supportemail <EmailAddress>]
# [saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>] [sadescription <ServiceAccountDescription>] # [saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>] [sadescription <ServiceAccountDescription>]
# [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)| # [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|
# (localkeysize 1024|2048|4096 [validityhours <Number>])| # (localkeysize 1024|2048|4096 [validityhours <Number>])|
# (yubikey yubikey_pin yubikey_slot AUTHENTICATION yubikey_serialnumber <String>)] # (yubikey yubikey_pin yubikey_slot AUTHENTICATION yubikey_serialnumber <String>)]
def doUseProject(): def doUseProject():
_checkForExistingProjectFiles([GC.Values[GC.OAUTH2SERVICE_JSON], GC.Values[GC.CLIENT_SECRETS_JSON]]) _checkForExistingProjectFiles([GC.Values[GC.OAUTH2SERVICE_JSON], GC.Values[GC.CLIENT_SECRETS_JSON]])
_, httpObj, login_hint, _, projectInfo, svcAcctInfo, create_key = _getLoginHintProjectInfo(False) _, httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key = _getLoginHintProjectInfo(False)
_createClientSecretsOauth2service(httpObj, login_hint, {}, projectInfo, svcAcctInfo, create_key) _createClientSecretsOauth2service(httpObj, login_hint, appInfo, projectInfo, svcAcctInfo, create_key)
# gam update project [[admin] <EmailAddress>] [<ProjectIDEntity>] # gam update project [[admin] <EmailAddress>] [<ProjectIDEntity>]
def doUpdateProject(): def doUpdateProject():
@@ -12577,12 +12587,6 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
else: else:
unknownArgumentExit() unknownArgumentExit()
def waitForCompletion(i):
sleep_time = i*5
if i > 3:
sys.stdout.write(Msg.WAITING_FOR_ITEM_CREATION_TO_COMPLETE_SLEEPING.format(Ent.Singular(Ent.SVCACCT), sleep_time))
time.sleep(sleep_time)
local_key_size = 2048 local_key_size = 2048
validityHours = 0 validityHours = 0
body = {} body = {}
@@ -12652,12 +12656,12 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
if retry == maxRetries: if retry == maxRetries:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e)) entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e))
return False return False
waitForCompletion(retry) _waitForSvcAcctCompletion(retry)
except GAPI.permissionDenied: except GAPI.permissionDenied:
if retry == maxRetries: if retry == maxRetries:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS) entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS)
return False return False
waitForCompletion(retry) _waitForSvcAcctCompletion(retry)
except GAPI.badRequest as e: except GAPI.badRequest as e:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e)) entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e))
return False return False
@@ -12670,7 +12674,7 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
new_data['private_key'] = '' new_data['private_key'] = ''
newPrivateKeyId = '' newPrivateKeyId = ''
break break
waitForCompletion(retry) _waitForSvcAcctCompletion(retry)
new_data['private_key_id'] = newPrivateKeyId new_data['private_key_id'] = newPrivateKeyId
oauth2service_data = _formatOAuth2ServiceData(new_data) oauth2service_data = _formatOAuth2ServiceData(new_data)
else: else:
@@ -12687,7 +12691,7 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
if retry == maxRetries: if retry == maxRetries:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS) entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS)
return False return False
waitForCompletion(retry) _waitForSvcAcctCompletion(retry)
except GAPI.badRequest as e: except GAPI.badRequest as e:
entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e)) entityActionFailedWarning([Ent.PROJECT, projectId, Ent.SVCACCT, clientEmail], str(e))
return False return False
@@ -12728,7 +12732,7 @@ def doProcessSvcAcctKeys(mode=None, iam=None, projectId=None, clientEmail=None,
if retry == maxRetries: if retry == maxRetries:
entityActionFailedWarning([Ent.SVCACCT_KEY, keyName], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS) entityActionFailedWarning([Ent.SVCACCT_KEY, keyName], Msg.UPDATE_PROJECT_TO_VIEW_MANAGE_SAKEYS)
break break
waitForCompletion(retry) _waitForSvcAcctCompletion(retry)
except GAPI.badRequest as e: except GAPI.badRequest as e:
entityActionFailedWarning([Ent.SVCACCT_KEY, keyName], str(e), i, count) entityActionFailedWarning([Ent.SVCACCT_KEY, keyName], str(e), i, count)
break break
@@ -15108,15 +15112,15 @@ def doCreateResoldCustomer():
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.invalid) as e: except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.invalid) as e:
entityActionFailedWarning([Ent.CUSTOMER_DOMAIN, body['customerDomain']], str(e)) entityActionFailedWarning([Ent.CUSTOMER_DOMAIN, body['customerDomain']], str(e))
# gam update resoldcustomer <CustomerID> [customer_auth_token <String>] <ResoldCustomerAttribute>+ # gam update resoldcustomer <CustomerID> <ResoldCustomerAttribute>+
def doUpdateResoldCustomer(): def doUpdateResoldCustomer():
res = buildGAPIObject(API.RESELLER) res = buildGAPIObject(API.RESELLER)
customerId = getString(Cmd.OB_CUSTOMER_ID) customerId = getString(Cmd.OB_CUSTOMER_ID)
customerAuthToken, body = _getResoldCustomerAttr() _, body = _getResoldCustomerAttr()
try: try:
callGAPI(res.customers(), 'patch', callGAPI(res.customers(), 'patch',
throwReasons=GAPI.RESELLER_THROW_REASONS, throwReasons=GAPI.RESELLER_THROW_REASONS,
customerId=customerId, body=body, customerAuthToken=customerAuthToken, fields='') customerId=customerId, body=body, fields='')
entityActionPerformed([Ent.CUSTOMER_ID, customerId]) entityActionPerformed([Ent.CUSTOMER_ID, customerId])
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.invalid) as e: except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden, GAPI.invalid) as e:
entityActionFailedWarning([Ent.CUSTOMER_ID, customerId], str(e)) entityActionFailedWarning([Ent.CUSTOMER_ID, customerId], str(e))
@@ -15135,6 +15139,7 @@ def doInfoResoldCustomer():
customerId=customerId) customerId=customerId)
if not FJQC.formatJSON: if not FJQC.formatJSON:
printKeyValueList(['Customer ID', customerInfo['customerId']]) printKeyValueList(['Customer ID', customerInfo['customerId']])
printKeyValueList(['Customer Type', customerInfo['customerType']])
printKeyValueList(['Customer Domain', customerInfo['customerDomain']]) printKeyValueList(['Customer Domain', customerInfo['customerDomain']])
if 'customerDomainVerified' in customerInfo: if 'customerDomainVerified' in customerInfo:
printKeyValueList(['Customer Domain Verified', customerInfo['customerDomainVerified']]) printKeyValueList(['Customer Domain Verified', customerInfo['customerDomainVerified']])
@@ -16569,7 +16574,7 @@ def doInfoAdminRole():
fieldsList.append('rolePrivileges') fieldsList.append('rolePrivileges')
else: else:
unknownArgumentExit() unknownArgumentExit()
fields = ','.join(set(fieldsList)) fields = getFieldsFromFieldsList(fieldsList)
try: try:
role = callGAPI(cd.roles(), 'get', role = callGAPI(cd.roles(), 'get',
throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.FAILED_PRECONDITION, throwReasons=[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.FAILED_PRECONDITION,
@@ -17706,9 +17711,9 @@ def _getOrgUnits(cd, orgUnitPath, fieldsList, listType, showParent, batchSubOrgs
if 'parentOrgUnitId' not in fieldsList: if 'parentOrgUnitId' not in fieldsList:
localFieldsList.append('parentOrgUnitId') localFieldsList.append('parentOrgUnitId')
deleteParentOrgUnitId = True deleteParentOrgUnitId = True
fields = ','.join(set(localFieldsList)) fields = getFieldsFromFieldsList(localFieldsList)
else: else:
fields = ','.join(set(fieldsList)) fields = getFieldsFromFieldsList(fieldsList)
listfields = f'organizationUnits({fields})' listfields = f'organizationUnits({fields})'
if listType == 'all' and orgUnitPath == '/': if listType == 'all' and orgUnitPath == '/':
printGettingAllAccountEntities(Ent.ORGANIZATIONAL_UNIT) printGettingAllAccountEntities(Ent.ORGANIZATIONAL_UNIT)
@@ -22170,8 +22175,7 @@ def printShowUserPeopleContacts(users):
if not fieldsList: if not fieldsList:
ofields = _getPersonFields(PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP, PEOPLE_CONTACTS_DEFAULT_FIELDS, fieldsList, parameters) ofields = _getPersonFields(PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP, PEOPLE_CONTACTS_DEFAULT_FIELDS, fieldsList, parameters)
else: else:
fieldsList = [PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP[field.lower()] for field in fieldsList if field.lower() in PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP] ofields = getFieldsFromFieldsList([PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP[field.lower()] for field in fieldsList if field.lower() in PEOPLE_OTHER_CONTACTS_FIELDS_CHOICE_MAP])
ofields = ','.join(set(fieldsList))
i, count, users = getEntityArgument(users) i, count, users = getEntityArgument(users)
for user in users: for user in users:
i += 1 i += 1
@@ -24785,7 +24789,7 @@ def doPrintCrOSActivity(entityList=None):
else: else:
sortRows = True sortRows = True
jcount = len(entityList) jcount = len(entityList)
fields = ','.join(set(fieldsList)) fields = getFieldsFromFieldsList(fieldsList)
svcargs = dict([('customerId', GC.Values[GC.CUSTOMER_ID]), ('deviceId', None), ('projection', projection), ('fields', fields)]+GM.Globals[GM.EXTRA_ARGS_LIST]) svcargs = dict([('customerId', GC.Values[GC.CUSTOMER_ID]), ('deviceId', None), ('projection', projection), ('fields', fields)]+GM.Globals[GM.EXTRA_ARGS_LIST])
method = getattr(cd.chromeosdevices(), 'get') method = getattr(cd.chromeosdevices(), 'get')
dbatch = cd.new_batch_http_request(callback=_callbackPrintCrOS) dbatch = cd.new_batch_http_request(callback=_callbackPrintCrOS)
@@ -25075,7 +25079,7 @@ def _showBrowser(browser, FJQC, i=0, count=0):
return return
printEntity([Ent.CHROME_BROWSER, browser['deviceId']], i, count) printEntity([Ent.CHROME_BROWSER, browser['deviceId']], i, count)
Ind.Increment() Ind.Increment()
showJSON(None, browser, timeObjects=BROWSER_TIME_OBJECTS) showJSON(None, browser, timeObjects=BROWSER_TIME_OBJECTS, dictObjectsKey={'machinePolicies': 'name'})
Ind.Decrement() Ind.Decrement()
BROWSER_FIELDS_CHOICE_MAP = { BROWSER_FIELDS_CHOICE_MAP = {
@@ -25115,11 +25119,13 @@ BROWSER_FIELDS_CHOICE_MAP = {
'user': 'annotatedUser', 'user': 'annotatedUser',
'virtualdeviceid': 'virtualDeviceId', 'virtualdeviceid': 'virtualDeviceId',
} }
BROWSER_ANNOTATED_FIELDS_LIST = ['annotatedAssetId', 'annotatedLocation', 'annotatedNotes', 'annotatedUser'] BROWSER_ANNOTATED_FIELDS_LIST = ['annotatedAssetId', 'annotatedLocation', 'annotatedNotes', 'annotatedUser', 'deviceId']
BROWSER_FULL_ACCESS_FIELDS = {'browsers', 'lastDeviceUsers', 'lastStatusReportTime', 'machinePolicies'} BROWSER_FULL_ACCESS_FIELDS = {'browsers', 'lastDeviceUsers', 'lastStatusReportTime', 'machinePolicies'}
# gam info browser <DeviceID> # gam info browser <DeviceID>
# [basic|full|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>] # (basic|full|annotated |
# (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
# (rawfields <BrowserFieldNameList>))
# [formatjson] # [formatjson]
def doInfoBrowsers(): def doInfoBrowsers():
cbcm = buildGAPIObject(API.CBCM) cbcm = buildGAPIObject(API.CBCM)
@@ -25127,6 +25133,7 @@ def doInfoBrowsers():
deviceId = getString(Cmd.OB_DEVICE_ID) deviceId = getString(Cmd.OB_DEVICE_ID)
projection = 'BASIC' projection = 'BASIC'
fieldsList = [] fieldsList = []
rawFields = None
FJQC = FormatJSONQuoteChar() FJQC = FormatJSONQuoteChar()
while Cmd.ArgumentsRemaining(): while Cmd.ArgumentsRemaining():
myarg = getArgument() myarg = getArgument()
@@ -25138,16 +25145,21 @@ def doInfoBrowsers():
fieldsList = [] fieldsList = []
elif getFieldsList(myarg, BROWSER_FIELDS_CHOICE_MAP, fieldsList, initialField='deviceId'): elif getFieldsList(myarg, BROWSER_FIELDS_CHOICE_MAP, fieldsList, initialField='deviceId'):
pass pass
elif myarg == 'rawfields':
projection = 'FULL'
rawFields = _getRawFields('deviceId')
else: else:
FJQC.GetFormatJSON(myarg) FJQC.GetFormatJSON(myarg)
if projection == 'BASIC' and set(fieldsList).intersection(BROWSER_FULL_ACCESS_FIELDS): if projection == 'BASIC' and set(fieldsList).intersection(BROWSER_FULL_ACCESS_FIELDS):
projection = 'FULL' projection = 'FULL'
fields = ','.join(set(fieldsList)) fields = getFieldsFromFieldsList(fieldsList) if not rawFields else rawFields
try: try:
browser = callGAPI(cbcm.chromebrowsers(), 'get', browser = callGAPI(cbcm.chromebrowsers(), 'get',
throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN], throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.FORBIDDEN],
customer=customerId, deviceId=deviceId, projection=projection, fields=fields) customer=customerId, deviceId=deviceId, projection=projection, fields=fields)
_showBrowser(browser, FJQC) _showBrowser(browser, FJQC)
except GAPI.invalidArgument as e:
entityActionFailedWarning([Ent.CHROME_BROWSER, deviceId], str(e))
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden): except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
checkEntityAFDNEorAccessErrorExit(None, Ent.CHROME_BROWSER, deviceId) checkEntityAFDNEorAccessErrorExit(None, Ent.CHROME_BROWSER, deviceId)
@@ -25348,7 +25360,7 @@ def doInfoChromeProfile():
pass pass
else: else:
FJQC.GetFormatJSON(myarg) FJQC.GetFormatJSON(myarg)
fields = ','.join(set(fieldsList)) fields = getFieldsFromFieldsList(fieldsList)
try: try:
profile = callGAPI(cm.customers().profiles(), 'get', profile = callGAPI(cm.customers().profiles(), 'get',
throwReasons=[GAPI.INVALID_ARGUMENT, GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED], throwReasons=[GAPI.INVALID_ARGUMENT, GAPI.NOT_FOUND, GAPI.PERMISSION_DENIED],
@@ -25480,13 +25492,19 @@ BROWSER_ORDERBY_CHOICE_MAP = {
# ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser)|(queries <QueryBrowserList>))|(select <BrowserEntity>)) # ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
# [querytime<String> <Time>] # [querytime<String> <Time>]
# [orderby <BrowserOrderByFieldName> [ascending|descending]] # [orderby <BrowserOrderByFieldName> [ascending|descending]]
# [basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>] # (basic|full|annotated |
# (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
# (rawfields <BrowserFieldNameList>))
# (<BrowserFieldName>* [fields <BrowserFieldNameList>]|(rawfields <BrowserFieldNameList>)
# [formatjson] # [formatjson]
# gam print browsers [todrive <ToDriveAttribute>*] # gam print browsers [todrive <ToDriveAttribute>*]
# ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser)|(queries <QueryBrowserList>))|(select <BrowserEntity>)) # ([ou|org|orgunit|browserou <OrgUnitPath>] [(query <QueryBrowser)|(queries <QueryBrowserList>))|(select <BrowserEntity>))
# [querytime<String> <Time>] # [querytime<String> <Time>]
# [orderby <BrowserOrderByFieldName> [ascending|descending]] # [orderby <BrowserOrderByFieldName> [ascending|descending]]
# [basic|full|allfields|annotated] <BrowserFieldName>* [fields <BrowserFieldNameList>] # (basic|full|annotated |
# (<BrowserFieldName>* [fields <BrowserFieldNameList>]) |
# (rawfields <BrowserFieldNameList>))
# (<BrowserFieldName>* [fields <BrowserFieldNameList>]|(rawfields <BrowserFieldNameList>)
# [sortheaders] [formatjson [quotechar <Character>]] # [sortheaders] [formatjson [quotechar <Character>]]
def doPrintShowBrowsers(): def doPrintShowBrowsers():
def _printBrowser(browser): def _printBrowser(browser):
@@ -25503,6 +25521,7 @@ def doPrintShowBrowsers():
csvPF = CSVPrintFile(['deviceId']) if Act.csvFormat() else None csvPF = CSVPrintFile(['deviceId']) if Act.csvFormat() else None
FJQC = FormatJSONQuoteChar(csvPF) FJQC = FormatJSONQuoteChar(csvPF)
fieldsList = [] fieldsList = []
rawFields = None
projection = 'BASIC' projection = 'BASIC'
orderBy = 'id' orderBy = 'id'
sortOrder = 'ASCENDING' sortOrder = 'ASCENDING'
@@ -25541,22 +25560,25 @@ def doPrintShowBrowsers():
sortHeaders = True sortHeaders = True
elif getFieldsList(myarg, BROWSER_FIELDS_CHOICE_MAP, fieldsList, initialField='deviceId'): elif getFieldsList(myarg, BROWSER_FIELDS_CHOICE_MAP, fieldsList, initialField='deviceId'):
pass pass
elif myarg == 'rawfields':
projection = 'FULL'
rawFields = _getRawFields('deviceId')
else: else:
FJQC.GetFormatJSONQuoteChar(myarg, True) FJQC.GetFormatJSONQuoteChar(myarg, True)
if projection == 'BASIC' and set(fieldsList).intersection(BROWSER_FULL_ACCESS_FIELDS): if projection == 'BASIC' and set(fieldsList).intersection(BROWSER_FULL_ACCESS_FIELDS):
projection = 'FULL' projection = 'FULL'
fields = getItemFieldsFromFieldsList('browsers', fieldsList)
if FJQC.formatJSON: if FJQC.formatJSON:
sortHeaders = False sortHeaders = False
substituteQueryTimes(queries, queryTimes) substituteQueryTimes(queries, queryTimes)
if entityList is None: if entityList is None:
fields = getItemFieldsFromFieldsList('browsers', fieldsList) if not rawFields else f'nextPageToken,browsers({rawFields})'
for query in queries: for query in queries:
printGettingAllAccountEntities(Ent.CHROME_BROWSER, query) printGettingAllAccountEntities(Ent.CHROME_BROWSER, query)
pageMessage = getPageMessage() pageMessage = getPageMessage()
try: try:
feed = yieldGAPIpages(cbcm.chromebrowsers(), 'list', 'browsers', feed = yieldGAPIpages(cbcm.chromebrowsers(), 'list', 'browsers',
pageMessage=pageMessage, messageAttribute='deviceId', pageMessage=pageMessage, messageAttribute='deviceId',
throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.INVALID_ORGUNIT, GAPI.FORBIDDEN], throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.INVALID_ARGUMENT, GAPI.INVALID_ORGUNIT, GAPI.FORBIDDEN],
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS, retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
customer=customerId, orgUnitPath=orgUnitPath, query=query, projection=projection, customer=customerId, orgUnitPath=orgUnitPath, query=query, projection=projection,
orderBy=orderBy, sortOrder=sortOrder, fields=fields) orderBy=orderBy, sortOrder=sortOrder, fields=fields)
@@ -25580,7 +25602,7 @@ def doPrintShowBrowsers():
else: else:
entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e)) entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e))
return return
except (GAPI.invalidOrgunit, GAPI.forbidden) as e: except (GAPI.invalidArgument, GAPI.invalidOrgunit, GAPI.forbidden) as e:
entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e)) entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e))
return return
except (GAPI.badRequest, GAPI.resourceNotFound): except (GAPI.badRequest, GAPI.resourceNotFound):
@@ -25588,15 +25610,17 @@ def doPrintShowBrowsers():
else: else:
sortRows = True sortRows = True
jcount = len(entityList) jcount = len(entityList)
fields = getFieldsFromFieldsList(fieldsList) fields = getFieldsFromFieldsList(fieldsList) if not rawFields else rawFields
j = 0 j = 0
for deviceId in entityList: for deviceId in entityList:
j += 1 j += 1
try: try:
browser = callGAPI(cbcm.chromebrowsers(), 'get', browser = callGAPI(cbcm.chromebrowsers(), 'get',
throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN], throwReasons=[GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.FORBIDDEN],
customer=customerId, deviceId=deviceId, projection=projection, fields=fields) customer=customerId, deviceId=deviceId, projection=projection, fields=fields)
_printBrowser(browser) _printBrowser(browser)
except GAPI.invalidArgument as e:
entityActionFailedWarning([Ent.CHROME_BROWSER, deviceId], str(e))
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden): except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
checkEntityAFDNEorAccessErrorExit(None, Ent.CHROME_BROWSER, deviceId) checkEntityAFDNEorAccessErrorExit(None, Ent.CHROME_BROWSER, deviceId)
if csvPF: if csvPF:
@@ -31733,6 +31757,8 @@ def doCreateGroup(ciGroupsAPI=False):
'query': getString(Cmd.OB_QUERY)}) 'query': getString(Cmd.OB_QUERY)})
elif ciGroupsAPI and myarg == 'makeowner': elif ciGroupsAPI and myarg == 'makeowner':
initialGroupConfig = 'WITH_INITIAL_OWNER' initialGroupConfig = 'WITH_INITIAL_OWNER'
elif ciGroupsAPI and myarg in {'security', 'makesecuritygroup'}:
body['labels'][CIGROUP_SECURITY_LABEL] = ''
elif myarg == 'verifynotinvitable': elif myarg == 'verifynotinvitable':
verifyNotInvitable = True verifyNotInvitable = True
else: else:
@@ -34609,8 +34635,11 @@ def doPrintShowGroupTree():
if csvPF: if csvPF:
csvPF.writeCSVfile('Group Tree') csvPF.writeCSVfile('Group Tree')
# gam create cigroup <EmailAddress> [copyfrom <GroupItem>] <GroupAttribute> # gam create cigroup <EmailAddress>
# [makeowner] [alias|aliases <CIGroupAliasList>] [dynamic <QueryDynamicGroup>] # [copyfrom <GroupItem>] <GroupAttribute>
# [makeowner] [alias|aliases <CIGroupAliasList>]
# [security|makesecuritygroup]
# [dynamic <QueryDynamicGroup>]
def doCreateCIGroup(): def doCreateCIGroup():
doCreateGroup(ciGroupsAPI=True) doCreateGroup(ciGroupsAPI=True)
@@ -37445,7 +37474,7 @@ def _doDeleteResourceCalendars(entityList):
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS, retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
customer=GC.Values[GC.CUSTOMER_ID], calendarResourceId=resourceId) customer=GC.Values[GC.CUSTOMER_ID], calendarResourceId=resourceId)
entityActionPerformed([Ent.RESOURCE_CALENDAR, resourceId], i, count) entityActionPerformed([Ent.RESOURCE_CALENDAR, resourceId], i, count)
except GAPI.serviceNotAvailable as e: except GAPI.serviceNotAvailable as e:
entityActionFailedWarning([Ent.RESOURCE_CALENDAR, resourceId], str(e), i, count) entityActionFailedWarning([Ent.RESOURCE_CALENDAR, resourceId], str(e), i, count)
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden): except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
checkEntityAFDNEorAccessErrorExit(cd, Ent.RESOURCE_CALENDAR, resourceId, i, count) checkEntityAFDNEorAccessErrorExit(cd, Ent.RESOURCE_CALENDAR, resourceId, i, count)
@@ -39164,10 +39193,12 @@ def _wipeCalendarEvents(user, origCal, calIds, count):
continue continue
try: try:
callGAPI(cal.calendars(), 'clear', callGAPI(cal.calendars(), 'clear',
throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID, GAPI.REQUIRED_ACCESS_LEVEL], throwReasons=GAPI.CALENDAR_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.INVALID,
GAPI.REQUIRED_ACCESS_LEVEL, GAPI.SERVICE_NOT_AVAILABLE],
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
calendarId=calId) calendarId=calId)
entityActionPerformed([Ent.CALENDAR, calId], i, count) entityActionPerformed([Ent.CALENDAR, calId], i, count)
except (GAPI.notFound, GAPI.forbidden, GAPI.invalid, GAPI.requiredAccessLevel) as e: except (GAPI.notFound, GAPI.forbidden, GAPI.invalid, GAPI.requiredAccessLevel, GAPI.serviceNotAvailable) as e:
entityActionFailedWarning([Ent.CALENDAR, calId], str(e), i, count) entityActionFailedWarning([Ent.CALENDAR, calId], str(e), i, count)
except GAPI.notACalendarUser: except GAPI.notACalendarUser:
userCalServiceNotEnabledWarning(calId, i, count) userCalServiceNotEnabledWarning(calId, i, count)
@@ -40424,9 +40455,10 @@ VAULT_SEARCH_METHODS_MAP = {
VAULT_CORPUS_ARGUMENT_MAP = { VAULT_CORPUS_ARGUMENT_MAP = {
'calendar': 'CALENDAR', 'calendar': 'CALENDAR',
'drive': 'DRIVE', 'drive': 'DRIVE',
'mail': 'MAIL', 'gemini': 'GEMINI',
'groups': 'GROUPS', 'groups': 'GROUPS',
'hangoutschat': 'HANGOUTS_CHAT', 'hangoutschat': 'HANGOUTS_CHAT',
'mail': 'MAIL',
'voice': 'VOICE', 'voice': 'VOICE',
} }
VAULT_COUNTS_CORPUS_ARGUMENT_MAP = { VAULT_COUNTS_CORPUS_ARGUMENT_MAP = {
@@ -40453,15 +40485,22 @@ VAULT_EXPORT_FORMAT_MAP = {
'ics': 'ICS', 'ics': 'ICS',
'mbox': 'MBOX', 'mbox': 'MBOX',
'pst': 'PST', 'pst': 'PST',
'xml': 'XML',
} }
VAULT_CORPUS_EXPORT_FORMATS = { VAULT_CORPUS_EXPORT_FORMATS = {
'CALENDAR': ['ICS', 'PST'], 'CALENDAR': ['ICS', 'PST'],
'DRIVE': [], 'DRIVE': [],
'GEMINI': ['XML'],
'GROUPS': ['MBOX', 'PST'], 'GROUPS': ['MBOX', 'PST'],
'HANGOUTS_CHAT': ['MBOX', 'PST'], 'HANGOUTS_CHAT': ['MBOX', 'PST'],
'MAIL': ['MBOX', 'PST'], 'MAIL': ['MBOX', 'PST'],
'VOICE' : ['MBOX', 'PST'], 'VOICE' : ['MBOX', 'PST'],
} }
VAULT_CSE_OPTION_MAP = {
'any': 'CLIENT_SIDE_ENCRYPTED_OPTION_ANY',
'encrypted': 'CLIENT_SIDE_ENCRYPTED_OPTION_ENCRYPTED',
'unencrypted': 'CLIENT_SIDE_ENCRYPTED_OPTION_UNENCRYPTED',
}
VAULT_EXPORT_REGION_MAP = { VAULT_EXPORT_REGION_MAP = {
'any': 'ANY', 'any': 'ANY',
'europe': 'EUROPE', 'europe': 'EUROPE',
@@ -40470,16 +40509,18 @@ VAULT_EXPORT_REGION_MAP = {
VAULT_CORPUS_OPTIONS_MAP = { VAULT_CORPUS_OPTIONS_MAP = {
'CALENDAR': 'calendarOptions', 'CALENDAR': 'calendarOptions',
'DRIVE': 'driveOptions', 'DRIVE': 'driveOptions',
'MAIL': 'mailOptions', 'GEMINI': 'geminiOptions',
'GROUPS': 'groupsOptions', 'GROUPS': 'groupsOptions',
'HANGOUTS_CHAT': 'hangoutsChatOptions', 'HANGOUTS_CHAT': 'hangoutsChatOptions',
'MAIL': 'mailOptions',
'VOICE': 'voiceOptions', 'VOICE': 'voiceOptions',
} }
VAULT_CORPUS_QUERY_MAP = { VAULT_CORPUS_QUERY_MAP = {
'CALENDAR': None, 'CALENDAR': None,
'DRIVE': 'driveQuery', 'DRIVE': 'driveQuery',
'MAIL': 'mailQuery', 'GEMINI': None,
'GROUPS': 'groupsQuery', 'GROUPS': 'groupsQuery',
'MAIL': 'mailQuery',
'HANGOUTS_CHAT': 'hangoutsChatQuery', 'HANGOUTS_CHAT': 'hangoutsChatQuery',
'VOICE': 'voiceQuery', 'VOICE': 'voiceQuery',
} }
@@ -40488,11 +40529,11 @@ VAULT_QUERY_ARGS = [
# calendar # calendar
'locationquery', 'peoplequery', 'minuswords', 'responsestatuses', 'caldendarversiondate', 'locationquery', 'peoplequery', 'minuswords', 'responsestatuses', 'caldendarversiondate',
# drive # drive
'driveversiondate', 'includeshareddrives', 'includeteamdrives', 'driveclientsideencryption', 'driveversiondate', 'includeshareddrives', 'includeteamdrives',
# hangoutsChat # hangoutsChat
'includerooms', 'includerooms',
# mail # mail
'excludedrafts', 'mailclientsideencryption', 'excludedrafts',
# voice # voice
'covereddata', 'covereddata',
] + list(VAULT_SEARCH_METHODS_MAP.keys()) ] + list(VAULT_SEARCH_METHODS_MAP.keys())
@@ -40549,12 +40590,16 @@ def _buildVaultQuery(myarg, query, corpusArgumentMap):
query.setdefault('driveOptions', {})['versionDate'] = getTimeOrDeltaFromNow() query.setdefault('driveOptions', {})['versionDate'] = getTimeOrDeltaFromNow()
elif myarg in {'includeshareddrives', 'includeteamdrives'}: elif myarg in {'includeshareddrives', 'includeteamdrives'}:
query.setdefault('driveOptions', {})['includeSharedDrives'] = getBoolean() query.setdefault('driveOptions', {})['includeSharedDrives'] = getBoolean()
elif myarg == 'driveclientsideencryption':
query.setdefault('driveOptions', {})['clientSideEncryptedOption'] = getChoice(VAULT_CSE_OPTION_MAP, mapChoice=True)
# hangoutsChat # hangoutsChat
elif myarg == 'includerooms': elif myarg == 'includerooms':
query['hangoutsChatOptions'] = {'includeRooms': getBoolean()} query['hangoutsChatOptions'] = {'includeRooms': getBoolean()}
# mail # mail
elif myarg == 'excludedrafts': elif myarg == 'excludedrafts':
query['mailOptions'] = {'excludeDrafts': getBoolean()} query['mailOptions'] = {'excludeDrafts': getBoolean()}
elif myarg == 'mailclientsideencryption':
query.setdefault('mailOptions', {})['clientSideEncryptedOption'] = getChoice(VAULT_CSE_OPTION_MAP, mapChoice=True)
# voice # voice
elif myarg == 'covereddata': elif myarg == 'covereddata':
query['voiceOptions'] = {'coveredData': getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)} query['voiceOptions'] = {'coveredData': getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)}
@@ -40569,7 +40614,7 @@ def _validateVaultQuery(body, corpusArgumentMap):
if body['query']['corpus'] != corpus: if body['query']['corpus'] != corpus:
body['exportOptions'].pop(options, None) body['exportOptions'].pop(options, None)
# gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice # gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone # (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
# (shareddrives|teamdrives <TeamDriveIDList>) | (rooms <RoomList>) | (sitesurl <URLList>) # (shareddrives|teamdrives <TeamDriveIDList>) | (rooms <RoomList>) | (sitesurl <URLList>)
# [scope <all_data|held_data|unprocessed_data>] # [scope <all_data|held_data|unprocessed_data>]
@@ -40577,10 +40622,12 @@ def _validateVaultQuery(body, corpusArgumentMap):
# [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>] # [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
# [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>] # [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
# [includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>] # [includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
# [driveclientsideencryption any|encrypted|unencrypted]
# [includerooms <Boolean>] # [includerooms <Boolean>]
# [excludedrafts <Boolean>] [format mbox|pst] # [excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
# [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>] # [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
# [covereddata calllogs|textmessages|voicemails] # [covereddata calllogs|textmessages|voicemails]
# [format ics|mbox|pst|xml]
# [region any|europe|us] [showdetails|returnidonly] # [region any|europe|us] [showdetails|returnidonly]
def doCreateVaultExport(): def doCreateVaultExport():
v = buildGAPIObject(API.VAULT) v = buildGAPIObject(API.VAULT)
@@ -48240,7 +48287,7 @@ def doPrintCourseTopics():
jcount = len(courseTopicIds) jcount = len(courseTopicIds)
if jcount == 0: if jcount == 0:
continue continue
fields = f'{",".join(set(fieldsList))}' fields = getFieldsFromFieldsList(fieldsList)
j = 0 j = 0
for courseTopicId in courseTopicIds: for courseTopicId in courseTopicIds:
j += 1 j += 1
@@ -48475,7 +48522,7 @@ def doPrintCourseWM(entityIDType, entityStateType):
jcount = len(courseWMIds) jcount = len(courseWMIds)
if jcount == 0: if jcount == 0:
continue continue
fields = f'{",".join(set(fieldsList))}' if fieldsList else None fields = getFieldsFromFieldsList(fieldsList)
j = 0 j = 0
for courseWMId in courseWMIds: for courseWMId in courseWMIds:
j += 1 j += 1
@@ -58882,6 +58929,8 @@ def initCopyMoveOptions(copyCmd):
'fileMimeTypes': set(), 'fileMimeTypes': set(),
'notMimeTypes': False, 'notMimeTypes': False,
'copySubFilesOwnedBy': None, 'copySubFilesOwnedBy': None,
'copyPermissionRoles': set(DRIVEFILE_ACL_ROLES_MAP.values()),
'copyPermissionTypes': set(DRIVEFILE_ACL_PERMISSION_TYPES),
} }
DUPLICATE_FILE_CHOICES = { DUPLICATE_FILE_CHOICES = {
@@ -58970,6 +59019,20 @@ def getCopyMoveOptions(myarg, copyMoveOptions):
copyMoveOptions['copyFileInheritedPermissions'] = getBoolean() copyMoveOptions['copyFileInheritedPermissions'] = getBoolean()
elif myarg == 'copyfilenoninheritedpermissions': elif myarg == 'copyfilenoninheritedpermissions':
copyMoveOptions['copyFileNonInheritedPermissions'] = COPY_NONINHERITED_PERMISSIONS_ALWAYS if getBoolean() else COPY_NONINHERITED_PERMISSIONS_NEVER copyMoveOptions['copyFileNonInheritedPermissions'] = COPY_NONINHERITED_PERMISSIONS_ALWAYS if getBoolean() else COPY_NONINHERITED_PERMISSIONS_NEVER
elif myarg == 'copypermissionroles':
copyMoveOptions['copyPermissionRoles'] = set()
for prole in getString(Cmd.OB_PERMISSION_ROLE_LIST).lower().replace(',', ' ').split():
if prole in DRIVEFILE_ACL_ROLES_MAP:
copyMoveOptions['copyPermissionRoles'].add(DRIVEFILE_ACL_ROLES_MAP[prole])
else:
invalidChoiceExit(prole, DRIVEFILE_ACL_ROLES_MAP, True)
elif myarg == 'copypermissiontypes':
copyMoveOptions['copyPermissionTypes'] = set()
for ptype in getString(Cmd.OB_PERMISSION_TYPE_LIST).lower().replace(',', ' ').split():
if ptype in DRIVEFILE_ACL_PERMISSION_TYPES:
copyMoveOptions['copyPermissionTypes'].add(ptype)
else:
invalidChoiceExit(ptype, DRIVEFILE_ACL_PERMISSION_TYPES, True)
elif myarg == 'copysheetprotectedranges': elif myarg == 'copysheetprotectedranges':
if getBoolean(): if getBoolean():
copyMoveOptions['copySheetProtectedRangesInheritedPermissions'] = True copyMoveOptions['copySheetProtectedRangesInheritedPermissions'] = True
@@ -59083,15 +59146,20 @@ def _copyPermissions(drive, user, i, count, j, jcount,
def isPermissionCopyable(kvList, permission): def isPermissionCopyable(kvList, permission):
role = permission['role'] role = permission['role']
emailAddress = permission.get('emailAddress', '') emailAddress = permission.get('emailAddress', '')
permissionType = permission['type']
domain = '' domain = ''
if copyMoveOptions['excludePermissionsFromDomains'] or copyMoveOptions['includePermissionsFromDomains']: if copyMoveOptions['excludePermissionsFromDomains'] or copyMoveOptions['includePermissionsFromDomains']:
if permission['type'] in {'group', 'user'}: if permissionType in {'group', 'user'}:
atLoc = emailAddress.find('@') atLoc = emailAddress.find('@')
if atLoc > 0: if atLoc > 0:
domain = emailAddress[atLoc+1:] domain = emailAddress[atLoc+1:]
elif permission['type'] == 'domain': elif permissionType == 'domain':
domain = permission.get('domain', '') domain = permission.get('domain', '')
if permission['inherited'] and not copyMoveOptions[copyInherited]: if role not in copyMoveOptions['copyPermissionRoles']:
notCopiedMessage = f'role {role} not selected'
elif permissionType not in copyMoveOptions['copyPermissionTypes']:
notCopiedMessage = f'type {permissionType} not selected'
elif permission['inherited'] and not copyMoveOptions[copyInherited]:
notCopiedMessage = 'inherited not selected' notCopiedMessage = 'inherited not selected'
elif not permission['inherited'] and copyMoveOptions[copyNonInherited] == COPY_NONINHERITED_PERMISSIONS_NEVER: elif not permission['inherited'] and copyMoveOptions[copyNonInherited] == COPY_NONINHERITED_PERMISSIONS_NEVER:
notCopiedMessage = 'noninherited not selected' notCopiedMessage = 'noninherited not selected'
@@ -59107,8 +59175,8 @@ def _copyPermissions(drive, user, i, count, j, jcount,
notCopiedMessage = f'domain {domain} excluded' notCopiedMessage = f'domain {domain} excluded'
elif domain and copyMoveOptions['includePermissionsFromDomains'] and domain not in copyMoveOptions['includePermissionsFromDomains']: elif domain and copyMoveOptions['includePermissionsFromDomains'] and domain not in copyMoveOptions['includePermissionsFromDomains']:
notCopiedMessage = f'domain {domain} not included' notCopiedMessage = f'domain {domain} not included'
elif permission.pop('deleted', False) or (permission['type'] in {'group', 'user'} and not emailAddress): elif permission.pop('deleted', False) or (permissionType in {'group', 'user'} and not emailAddress):
notCopiedMessage = f"{permission['type']} deleted or has blank email address" notCopiedMessage = f"{permissionType} deleted or has blank email address"
elif ((copyInherited == 'copySheetProtectedRangesInheritedPermissions' and copyMoveOptions[copyInherited]) or elif ((copyInherited == 'copySheetProtectedRangesInheritedPermissions' and copyMoveOptions[copyInherited]) or
(copyNonInherited == 'copySheetProtectedRangesNonInheritedPermissions' and (copyNonInherited == 'copySheetProtectedRangesNonInheritedPermissions' and
copyMoveOptions[copyNonInherited] != COPY_NONINHERITED_PERMISSIONS_NEVER)): copyMoveOptions[copyNonInherited] != COPY_NONINHERITED_PERMISSIONS_NEVER)):
@@ -59546,6 +59614,8 @@ copyReturnItemMap = {
# [copysubfolderpermissions [<Boolean>]] # [copysubfolderpermissions [<Boolean>]]
# [copysubfolderinheritedpermissions [<Boolean>]] # [copysubfolderinheritedpermissions [<Boolean>]]
# [copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders] # [copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders]
# [copypermissionroles <DriveFileACLRoleList>]
# [copypermissiontypes <DriveFileACLTypeList>]
# [excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>] # [excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
# (mappermissionsdomain <DomainName> <DomainName>)* # (mappermissionsdomain <DomainName> <DomainName>)*
# [copysheetprotectedranges [<Boolean>]] # [copysheetprotectedranges [<Boolean>]]
@@ -60360,6 +60430,8 @@ def _updateMoveFilePermissions(drive, user, i, count,
# [copysubfolderpermissions [<Boolean>]] # [copysubfolderpermissions [<Boolean>]]
# [copysubfolderinheritedpermissions [<Boolean>]] # [copysubfolderinheritedpermissions [<Boolean>]]
# [copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders] # [copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders]
# [copypermissionroles <DriveFileACLRoleList>]
# [copypermissiontypes <DriveFileACLTypeList>]
# [synctopfoldernoniheritedpermissions [<Boolean>]] [syncsubfoldernoninheritedpermissions [<Boolean>]] # [synctopfoldernoniheritedpermissions [<Boolean>]] [syncsubfoldernoninheritedpermissions [<Boolean>]]
# [excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>] # [excludepermissionsfromdomains|includepermissionsfromdomains <DomainNameList>]
# (mappermissionsdomain <DomainName> <DomainName>)* # (mappermissionsdomain <DomainName> <DomainName>)*
@@ -65470,7 +65542,7 @@ def infoSharedDrive(users, useDomainAdminAccess=False):
guiRoles = getBoolean() guiRoles = getBoolean()
else: else:
FJQC.GetFormatJSON(myarg) FJQC.GetFormatJSON(myarg)
fields = ','.join(set(fieldsList)) if fieldsList else '*' fields = getFieldsFromFieldsList(fieldsList) if fieldsList else '*'
i, count, users = getEntityArgument(users) i, count, users = getEntityArgument(users)
for user in users: for user in users:
i += 1 i += 1
@@ -69376,13 +69448,18 @@ LABEL_COUNTS_FIELDS = ','.join(LABEL_COUNTS_FIELDS_LIST)
def printShowLabels(users): def printShowLabels(users):
def _buildLabelTree(labels): def _buildLabelTree(labels):
def _checkChildLabel(label): def _checkChildLabel(label):
if label.find('/') != -1: labelItemList = label.split('/')
(parent, base) = label.rsplit('/', 1) i = len(labelItemList)-1
while i > 0:
parent = '/'.join(labelItemList[:i])
base = '/'.join(labelItemList[i:])
if parent in labelTree: if parent in labelTree:
if label in labelTree: if label in labelTree:
labelTree[label]['info']['base'] = base labelTree[label]['info']['base'] = base
labelTree[parent]['children'].append(labelTree.pop(label)) labelTree[parent]['children'].append(labelTree.pop(label))
_checkChildLabel(parent) _checkChildLabel(parent)
return
i -= 1
labelTree = {} labelTree = {}
for label in labels['labels']: for label in labels['labels']:

View File

@@ -71,7 +71,6 @@ GROUPSMIGRATION = 'groupsmigration'
GROUPSSETTINGS = 'groupssettings' GROUPSSETTINGS = 'groupssettings'
IAM = 'iam' IAM = 'iam'
IAM_CREDENTIALS = 'iamcredentials' IAM_CREDENTIALS = 'iamcredentials'
IAP = 'iap'
KEEP = 'keep' KEEP = 'keep'
LICENSING = 'licensing' LICENSING = 'licensing'
LOOKERSTUDIO = 'datastudio' LOOKERSTUDIO = 'datastudio'
@@ -185,7 +184,6 @@ PROJECT_APIS = [
'groupsmigration.googleapis.com', 'groupsmigration.googleapis.com',
'groupssettings.googleapis.com', 'groupssettings.googleapis.com',
'iam.googleapis.com', 'iam.googleapis.com',
'iap.googleapis.com',
'keep.googleapis.com', 'keep.googleapis.com',
'licensing.googleapis.com', 'licensing.googleapis.com',
'meet.googleapis.com', 'meet.googleapis.com',
@@ -250,7 +248,6 @@ _INFO = {
GROUPSSETTINGS: {'name': 'Groups Settings API', 'version': 'v1', 'v2discovery': True}, GROUPSSETTINGS: {'name': 'Groups Settings API', 'version': 'v1', 'v2discovery': True},
IAM: {'name': 'Identity and Access Management API', 'version': 'v1', 'v2discovery': True}, IAM: {'name': 'Identity and Access Management API', 'version': 'v1', 'v2discovery': True},
IAM_CREDENTIALS: {'name': 'Identity and Access Management Credentials API', 'version': 'v1', 'v2discovery': True}, IAM_CREDENTIALS: {'name': 'Identity and Access Management Credentials API', 'version': 'v1', 'v2discovery': True},
IAP: {'name': 'Cloud Identity-Aware Proxy API', 'version': 'v1', 'v2discovery': True},
KEEP: {'name': 'Keep API', 'version': 'v1', 'v2discovery': True}, KEEP: {'name': 'Keep API', 'version': 'v1', 'v2discovery': True},
LICENSING: {'name': 'License Manager API', 'version': 'v1', 'v2discovery': True}, LICENSING: {'name': 'License Manager API', 'version': 'v1', 'v2discovery': True},
LOOKERSTUDIO: {'name': 'Looker Studio API', 'version': 'v1', 'v2discovery': True, 'localjson': True}, LOOKERSTUDIO: {'name': 'Looker Studio API', 'version': 'v1', 'v2discovery': True, 'localjson': True},

View File

@@ -924,6 +924,7 @@ class GamCLArgs():
OB_EXPORT_ITEM = 'ExportItem' OB_EXPORT_ITEM = 'ExportItem'
OB_FIELD_NAME = 'FieldName' OB_FIELD_NAME = 'FieldName'
OB_FIELD_NAME_LIST = "FieldNameList" OB_FIELD_NAME_LIST = "FieldNameList"
OB_FIELDS = 'Fields'
OB_FILE_NAME = 'FileName' OB_FILE_NAME = 'FileName'
OB_FILE_NAME_FIELD_NAME = OB_FILE_NAME+'(:'+OB_FIELD_NAME+')+' OB_FILE_NAME_FIELD_NAME = OB_FILE_NAME+'(:'+OB_FIELD_NAME+')+'
OB_FILE_NAME_OR_URL = 'FileName|URL' OB_FILE_NAME_OR_URL = 'FileName|URL'

View File

@@ -40,21 +40,43 @@ sign in as {0} and accept the Terms of Service (ToS). As soon as you've accepted
PROJECT_STILL_BEING_CREATED_SLEEPING = 'Project still being created. Sleeping {0} seconds\n' PROJECT_STILL_BEING_CREATED_SLEEPING = 'Project still being created. Sleeping {0} seconds\n'
FAILED_TO_CREATE_PROJECT = 'Failed to create project: {0}\n' FAILED_TO_CREATE_PROJECT = 'Failed to create project: {0}\n'
SETTING_GAM_PROJECT_CONSENT_SCREEN = 'Setting GAM project consent screen...\n' SETTING_GAM_PROJECT_CONSENT_SCREEN_CREATING_CLIENT = 'Setting GAM project consent screen, creating client...\n'
CREATE_PROJECT_INSTRUCTIONS = ''' CREATE_CLIENT_INSTRUCTIONS = '''
Please go to: Please go to:
{0} {0}
1. Choose "Desktop App" or "Other" for "Application type". 1. If "+ CREATE CLIENT" is on the screen, skip to step 14
2. Enter "GAM" or another desired value for "Name". 2. Click "GET STARTED"
3. Click the blue "Create" button. 3. Under "App Information", enter {1} or another value in "App name *"
4. Copy your "Client ID" value that shows on the next page. 4. Under "App Information", enter {2} in "User support email *"
5. Click "NEXT"
6. Under "Audience", choose INTERNAL
7. Click "NEXT"
8. Under, "Contact Information", enter an email address in "Email addresses *"
9. Click "NEXT"
10. Under "Finish", click "I agree to the Google API Services: User Data Policy."
11. Click "CONTINUE"
12. Click "CREATE"
13. Click "Clients" in the left-hand column
14. Click "+ CREATE CLIENT"
15. Choose "Desktop App" for "Application type"
16. Enter {1} or another value in "Name *"
17. Click "Create"
18. Under "Name", click your client name
19. Copy the "Client ID" value under "Additional information"
20. Paste it at the "Enter your Client ID: " prompt in your terminal
21. Press return/enter in your terminal
22. Switch back to the browser
23. Copy the "Client secret" value under "Client Secrets"
24. Paste it at the "Enter your Client Secret: " prompt in your terminal
25. Press return/enter in your terminal
26. Switch back to the browser
27. Click "CANCEL"
28. These steps are complete
''' '''
ENTER_YOUR_CLIENT_ID = '\nEnter your Client ID: ' ENTER_YOUR_CLIENT_ID = '\nEnter your Client ID: '
GO_BACK_TO_YOUR_BROWSER_AND_COPY_YOUR_CLIENT_SECRET_VALUE = '\n5. Go back to your browser and copy your "Client Secret" value.\n'
ENTER_YOUR_CLIENT_SECRET = '\nEnter your Client Secret: ' ENTER_YOUR_CLIENT_SECRET = '\nEnter your Client Secret: '
GO_BACK_TO_YOUR_BROWSER_AND_CLICK_OK_TO_CLOSE_THE_OAUTH_CLIENT_POPUP = '\n6. Go back to your browser and click OK to close the "OAuth client" popup if it\'s still open.\n'
IS_NOT_A_VALID_CLIENT_ID = ''' IS_NOT_A_VALID_CLIENT_ID = '''
{0} {0}
@@ -78,12 +100,12 @@ Please go to:
https://admin.google.com/ac/owl/list?tab=configuredApps https://admin.google.com/ac/owl/list?tab=configuredApps
1. Click on: Configure new app > OAuth App Name Or Client ID. 1. Click on: Configure new app
2. Enter the following Client ID value: 2. Enter the following Client ID value in Search for app:
{1} {1}
3. Press Search, select the {0} app, press Select, check the box and press Select. 3. Press Search, select the {0} app, click
4. Keep the default scope or select a preferred scope that includes your GAM admin. 4. Keep the default scope or select a preferred scope that includes your GAM admin.
5. Press Continue 5. Press Continue
6. Select Trusted radio button, press Continue and Finish. 6. Select Trusted radio button, press Continue and Finish.

View File

@@ -11,4 +11,4 @@ lxml
passlib>=1.7.2 passlib>=1.7.2
pathvalidate pathvalidate
python-dateutil python-dateutil
yubikey-manager>=5.0 yubikey-manager[yubikey]>=5.0