Compare commits

..

44 Commits
v3.8 ... v4.01

Author SHA1 Message Date
Jay Lee
3c85da292e GAM 4.01 2016-11-02 15:28:15 -04:00
Jay Lee
c7b5251b03 prompt for admin email and use as hint 2016-11-02 15:23:43 -04:00
Jay Lee
5307a560bd fix service account create call 2016-11-02 14:45:17 -04:00
Jay Lee
059e6a1813 fix gam version 2016-11-02 13:30:42 -04:00
Jay Lee
395a561b8c GAM v4.0 2016-11-02 13:17:44 -04:00
Jay Lee
6c3a744ed3 improve project create instructions. 2016-11-02 13:15:10 -04:00
Jay Lee
907126d642 gam version simple, save project files to GAM path 2016-11-02 12:59:38 -04:00
Jay Lee
9e4506141e add message to restart term 2016-11-02 12:43:40 -04:00
Jay Lee
5deac72484 authorize admin and check service account 2016-11-02 11:40:00 -04:00
Jay Lee
9def6e6d73 run alias command. 2016-11-02 11:02:11 -04:00
Jay Lee
fefe9de384 further improvements to scope check. 2016-11-02 10:20:27 -04:00
Jay Lee
f8341be9ea add statement about extract starting. 2016-11-02 09:47:12 -04:00
Jay Lee
3c50f464cc add -p argument to disable profile update 2016-11-02 09:33:46 -04:00
Jay Lee
6961a0e1b3 more details on check serviceaccount 2016-11-01 22:32:33 -04:00
Jay Lee
3fa6cde6b0 another change to improve missing scope errors 2016-11-01 22:23:34 -04:00
Jay Lee
4129e05f5e check serviceaccount command, better error on missing service scopes 2016-11-01 22:13:45 -04:00
Jay Lee
42137297a1 extra space 2016-11-01 12:17:46 -04:00
Jay Lee
bc64e9a67c fix color escaping on MacOS 2016-11-01 12:16:49 -04:00
Jay Lee
e1ec8b8649 fix color function calls 2016-11-01 12:07:51 -04:00
Jay Lee
b9ec06807b message color and more error checking. 2016-11-01 12:01:33 -04:00
Jay Lee
e3d826cdb3 catch tar errors and exit. 2016-11-01 11:53:30 -04:00
Jay Lee
4306dba9f1 Merge branch 'master' of https://github.com/jay0lee/GAM 2016-11-01 11:44:30 -04:00
Jay Lee
cf397c228c MacOS >= 10.10 please 2016-11-01 11:44:05 -04:00
Jay Lee
a2a6719333 Update macos-build.sh 2016-10-31 14:57:21 -04:00
Jay Lee
7cef626a6f Add GAM to Windows PATH 2016-10-31 14:45:31 -04:00
Jay Lee
be44ae4322 newlines and stuff 2016-10-31 13:33:33 -04:00
Jay Lee
4c00b54ad4 no trailing slash 2016-10-31 13:30:22 -04:00
Jay Lee
8508ee4afa force to lower 2016-10-31 13:15:39 -04:00
Jay Lee
17b2c4091d login_hint, not hint 2016-10-31 12:23:45 -04:00
Jay Lee
925f4532bc IndexError, not KeyError 2016-10-31 12:20:04 -04:00
Jay Lee
786bbe5609 handle ToS not accepted yet for project create 2016-10-31 12:17:43 -04:00
Jay Lee
6be52c8b3c MacOS doesn't seem to like ~ as /home/jay 2016-10-31 09:37:17 -04:00
Jay Lee
2c2046a784 arguments and further improvements to gam-install.sh 2016-10-31 09:29:50 -04:00
Jay Lee
20de452685 Linux and MacOS install script 2016-10-31 05:57:47 -04:00
Jay Lee
df603937ee fix service account url display 2016-10-29 14:56:33 -04:00
Jay Lee
315a1db144 Merge branch 'master' of https://github.com/jay0lee/GAM 2016-10-29 14:09:42 -04:00
Jay Lee
968c096a99 "gam create project" rough draft. Needs a lot of work but first steps towards solving #309 2016-10-29 14:09:08 -04:00
Jay Lee
6703519d36 remove email-audit include 2016-10-28 12:07:53 -04:00
Jay Lee
9dd8696c1e remove email-audit include 2016-10-28 12:07:28 -04:00
Jay Lee
df7c12b737 Remove email-audit include 2016-10-28 12:07:06 -04:00
Jay Lee
7cfba0ada1 remove email-audit-v1.json file 2016-10-28 12:06:16 -04:00
Jay Lee
2ee5109424 remove email-audit API mapping 2016-10-28 12:05:44 -04:00
Jay Lee
721f787f0f Update macos-gam.spec 2016-10-28 10:56:08 -04:00
Jay Lee
bc62f7a9f6 Update linux-gam.spec 2016-10-28 10:55:37 -04:00
8 changed files with 521 additions and 71 deletions

View File

@@ -1,34 +0,0 @@
{
"kind": "discovery#restDescription",
"discoveryVersion": "v1",
"id": "email-audit:v1",
"name": "email-audit",
"version": "v1",
"revision": "20130823",
"title": "Email Audit API",
"description": "Lets you perform Google Apps email audits",
"ownerDomain": "google.com",
"ownerName": "Google",
"icons": {
"x16": "http://www.google.com/images/icons/product/search-16.gif",
"x32": "http://www.google.com/images/icons/product/search-32.gif"
},
"documentationLink": "https://developers.google.com/admin-sdk/email-audit",
"protocol": "rest",
"baseUrl": "https://apps-apis.google.com/",
"rootUrl": "https://apps-apis.google.com/",
"servicePath": "/a/feeds/compliance/audit/",
"auth": {
"oauth2": {
"scopes": {
"https://apps-apis.google.com/a/feeds/compliance/audit/": {
"description": "Manage email audits"
}
}
}
},
"schemas": {
},
"resources": {
}
}

274
src/gam-install.sh Executable file
View File

@@ -0,0 +1,274 @@
#!/usr/bin/env bash
usage()
{
cat << EOF
GAM installation script.
OPTIONS:
-h show help.
-d Directory where gam folder will be installed. Default is \$HOME/bin/
-a Architecture to install (i386, x86_64, arm). Default is to detect your arch with "uname -m".
-o OS we are running (linux, macos). Default is to detect your OS with "uname -s".
-p Profile update (true, false). Should script add gam command to environment. Default is true.
-u Admin user email address to use with GAM. Default is to prompt.
-v Version to install (latest, prerelease, draft, 3.8, etc). Default is latest.
EOF
}
target_dir="$HOME/bin"
gamarch=$(uname -m)
gamos=$(uname -s)
update_profile=true
gamversion="latest"
adminuser=""
while getopts "hd:a:o:p:u:v:" OPTION
do
case $OPTION in
h) usage; exit;;
d) target_dir=$OPTARG;;
a) gamarch=$OPTARG;;
o) gamos=$OPTARG;;
p) update_profile=$OPTARG;;
u) adminuser=$OPTARG;;
v) gamversion=$OPTARG;;
?) usage; exit;;
esac
done
update_profile() {
[ -f "$1" ] || return 1
grep -F "$alias_line" "$1" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo_yellow "Adding gam alias to profile file $1."
echo -e "\n$alias_line" >> "$1"
else
echo_yellow "gam alias already exists in profile file $1. Skipping add."
fi
}
echo_red()
{
echo -e "\x1B[1;31m$1"
echo -e '\x1B[0m'
}
echo_green()
{
echo -e "\x1B[1;32m$1"
echo -e '\x1B[0m'
}
echo_yellow()
{
echo -e "\x1B[1;33m$1"
echo -e '\x1B[0m'
}
case $gamos in
[lL]inux)
gamos="linux"
case $gamarch in
x86_64) gamfile="linux-x86_64.tar.xz";;
i?86) gamfile="linux-i686.tar.xz";;
arm*) gamfile="linux-armv7l.tar.xz";;
*)
echo_red "ERROR: this installer currently only supports i386, x86_64 and arm Linux. Looks like you're running on $gamarch. Exiting."
exit
esac
;;
[Mm]ac[Oo][sS]|[Dd]arwin)
osver=$(sw_vers -productVersion | awk -F'.' '{print $2}')
if (( $osver < 10 )); then
echo_red "ERROR: GAM currently requires MacOS 10.10 or newer. You are running MacOS 10.$osver. Please upgrade."
exit
else
echo_green "Good, you're running MacOS 10.$osver..."
fi
gamos="macos"
gamfile="macos.tar.xz"
;;
*)
echo_red "Sorry, this installer currently only supports Linux and MacOS. Looks like you're runnning on $gamos. Exiting."
exit
;;
esac
if [ "$gamversion" == "latest" -o "$gamversion" == "prerelease" -o "$gamversion" == "draft" ]; then
release_url="https://api.github.com/repos/jay0lee/GAM/releases"
else
release_url="https://api.github.com/repos/jay0lee/GAM/releases/tags/v$gamversion"
fi
echo_yellow "Checking GitHub URL $release_url for $gamversion GAM release..."
release_json=$(curl -s $release_url 2>&1 /dev/null)
echo_yellow "Getting file and download URL..."
# Python is sadly the nearest to universal way to safely handle JSON with Bash
# At least this code should be compatible with just about any Python version ever
# unlike GAM itself. If some users don't have Python we can try grep / sed / etc
# but that gets really ugly
pycode="import json
import sys
attrib = sys.argv[1]
gamversion = sys.argv[2]
release = json.load(sys.stdin)
if type(release) is list:
for a_release in release:
if a_release['prerelease'] and gamversion != 'prerelease':
continue
elif a_release['draft'] and gamversion != 'draft':
continue
release = a_release
break
for asset in release['assets']:
if asset[sys.argv[1]].endswith('$gamfile'):
print asset[sys.argv[1]]
break"
browser_download_url=$(echo "$release_json" | python -c "$pycode" browser_download_url $gamversion)
name=$(echo "$release_json" | python -c "$pycode" name $gamversion)
# Temp dir for archive
temp_archive_dir=$(mktemp -d)
echo_yellow "Downloading file $name from $browser_download_url to $temp_archive_dir."
# Save archive to temp w/o losing our path
(cd $temp_archive_dir && curl -O -L $browser_download_url)
mkdir -p $target_dir
echo_yellow "Extracting archive to $target_dir"
tar xf $temp_archive_dir/$name -C $target_dir
rc=$?
if (( $rc != 0 )); then
echo_red "ERROR: extracting the GAM archive with tar failed with error $rc. Exiting."
exit
else
echo_green "Finished extracting GAM archive."
fi
# Update profile to add gam command
if [ "$update_profile" = true ]; then
alias_line="alias gam=\"$target_dir/gam/gam\""
if [ "$gamos" == "linux" ]; then
update_profile "$HOME/.bashrc" || update_profile "$HOME/.bash_profile"
elif [ "$gamos" == "macos" ]; then
update_profile "$HOME/.profile" || update_profile "$HOME/.bash_profile"
fi
else
echo_yellow "skipping profile update."
fi
while true; do
read -p "Can you run a full browser on this machine? (usually Y for MacOS, N for Linux if you SSH into this machine) " yn
case $yn in
[Yy]*)
break
;;
[Nn]*)
touch $target_dir/gam/nobrowser.txt > /dev/null 2>&1
break
;;
*)
echo_red "Please answer yes or no."
;;
esac
done
echo
project_created=false
while true; do
read -p "GAM is now installed. Are you ready to set up a Google API project for GAM? (yes or no) " yn
case $yn in
[Yy]*)
if [ "$adminuser" == "" ]; then
read -p "Please enter your G Suite admin email address: " adminuser
fi
$target_dir/gam/gam create project $adminuser
rc=$?
if (( $rc == 0 )); then
echo_green "Project creation complete."
project_created=true
break
else
echo_red "Projection creation failed. Trying again. Say N to skip projection creation."
fi
;;
[Nn]*)
echo -e "\nYou can create an API project later by running:\n\ngam create project\n"
break
;;
*)
echo_red "Please answer yes or no."
;;
esac
done
admin_authorized=false
while $project_created; do
read -p "Are you ready to authorize GAM to perform G Suite management operations as your admin account? (yes or no) " yn
case $yn in
[Yy]*)
$target_dir/gam/gam oauth create $adminuser
rc=$?
if (( $rc == 0 )); then
echo_green "Admin authorization complete."
admin_authorized=true
break
else
echo_red "Admin authorization failed. Trying again. Say N to skip admin authorization."
fi
;;
[Nn]*)
echo -e "\nYou can authorize an admin later by running:\n\ngam oauth create\n"
break
;;
*)
echo_red "Please answer yes or no."
;;
esac
done
service_account_authorized=false
while $project_created; do
read -p "Are you ready to authorize GAM to manage G Suite user data and settings? (yes or no) " yn
case $yn in
[Yy]*)
echo_yellow "Great! Checking service account scopes.This will fail the first time. Follow the steps to authorize and retry. It can take a few minutes for scopes to PASS after they've been authorized in the admin console."
$target_dir/gam/gam user $adminuser check serviceaccount
rc=$?
if (( $rc == 0 )); then
echo_green "Service account authorization complete."
service_account_authorized=true
break
else
echo_red "Service account authorization failed. Confirm you entered the scopes correctly in the admin console. It can take a few minutes for scopes to PASS after they are entered in the admin console so if you're sure you entered them correctly, go grab a coffee and then hit Y to try again. Say N to skip admin authorization."
fi
;;
[Nn]*)
echo -e "\nYou can authorize a service account later by running:\n\ngam check serviceaccount\n"
break
;;
*)
echo_red "Please answer yes or no."
;;
esac
done
echo_green "Here's information about your new GAM installation:"
$target_dir/gam/gam version
rc=$?
if (( $rc != 0 )); then
echo_red "ERROR: Failed running GAM for the first time with $rc. Please report this error to GAM mailing list. Exiting."
exit
fi
echo_green "GAM installation and setup complete!"
if [ "$update_profile" = true ]; then
echo_green "Please restart your terminal shell or to get started right away run:\n\n$alias_line"
fi
# Clean up after ourselves even if we are killed with CTRL-C
trap "rm -rf $temp_archive_dir" EXIT

View File

@@ -23,7 +23,7 @@ For more information, see http://git.io/gam
"""
__author__ = u'Jay Lee <jay0lee@gmail.com>'
__version__ = u'3.8'
__version__ = u'4.01'
__license__ = u'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
import sys
@@ -819,24 +819,32 @@ def doGAMCheckForUpdates(forceCheck=False):
return
def doGAMVersion(checkForCheck=True):
force_check = False
simple = False
i = 2
while i < len(sys.argv):
myarg = sys.argv[i].lower().replace(u'_', u'')
force_check = True
if myarg == u'check':
force_check = True
i += 1
elif myarg == u'simple':
simple = True
i += 1
else:
print u'ERROR: %s is not a valid argument for "gam version"' % sys.argv[i]
sys.exit(2)
if simple:
sys.stdout.write(__version__)
sys.exit(0)
import struct
print u'GAM {0} - {1}\n{2}\nPython {3}.{4}.{5} {6}-bit {7}\ngoogle-api-python-client {8}\n{9} {10}\nPath: {11}'.format(__version__, GAM_URL,
__author__,
sys.version_info[0], sys.version_info[1], sys.version_info[2],
struct.calcsize(u'P')*8, sys.version_info[3],
googleapiclient.__version__,
platform.platform(), platform.machine(),
GM_Globals[GM_GAM_PATH])
if checkForCheck:
i = 2
while i < len(sys.argv):
myarg = sys.argv[i].lower().replace(u'_', u'')
if myarg == u'check':
doGAMCheckForUpdates(forceCheck=True)
i += 1
else:
print u'ERROR: %s is not a valid argument for "gam version"' % sys.argv[i]
sys.exit(2)
version_data = u'GAM {0} - {1}\n{2}\nPython {3}.{4}.{5} {6}-bit {7}\ngoogle-api-python-client {8}\n{9} {10}\nPath: {11}'
print version_data.format(__version__, GAM_URL, __author__, sys.version_info[0],
sys.version_info[1], sys.version_info[2], struct.calcsize(u'P')*8,
sys.version_info[3], googleapiclient.__version__, platform.platform(),
platform.machine(), GM_Globals[GM_GAM_PATH])
if checkForCheck or force_check:
doGAMCheckForUpdates(forceCheck=True)
def handleOAuthTokenError(e, soft_errors):
if e.message in OAUTH2_TOKEN_ERRORS:
@@ -960,7 +968,8 @@ def callGAPI(service, function,
handleOAuthTokenError(e, soft_errors or GAPI_SERVICE_NOT_AVAILABLE in throw_reasons)
if GAPI_SERVICE_NOT_AVAILABLE in throw_reasons:
raise GAPI_serviceNotAvailable(e.message)
entityUnknownWarning(u'User', GM_Globals[GM_CURRENT_API_USER], 0, 0)
print u'ERROR: user %s: %s' % (GM_Globals[GM_CURRENT_API_USER], e)
#entityUnknownWarning(u'User', GM_Globals[GM_CURRENT_API_USER], 0, 0)
return None
except httplib2.CertificateValidationUnsupported:
noPythonSSLExit()
@@ -1032,7 +1041,6 @@ API_VER_MAPPING = {
u'datatransfer': u'datatransfer_v1',
u'directory': u'directory_v1',
u'drive': u'v2',
u'email-audit': u'v1',
u'email-settings': u'v2',
u'gmail': u'v1',
u'groupssettings': u'v1',
@@ -1161,17 +1169,19 @@ def getSvcAcctAPIversionHttpService(api):
except (ValueError, KeyError):
invalidJSONExit(disc_file)
def buildGAPIServiceObject(api, act_as):
def buildGAPIServiceObject(api, act_as, use_scopes=None):
_, http, service = getSvcAcctAPIversionHttpService(api)
GM_Globals[GM_CURRENT_API_USER] = act_as
GM_Globals[GM_CURRENT_API_SCOPES] = API_SCOPE_MAPPING[api]
credentials = getSvcAcctCredentials(GM_Globals[GM_CURRENT_API_SCOPES], act_as)
if not use_scopes:
use_scopes = GM_Globals[GM_CURRENT_API_SCOPES]
credentials = getSvcAcctCredentials(use_scopes, act_as)
try:
service._http = credentials.authorize(http)
except httplib2.ServerNotFoundError as e:
systemErrorExit(4, e)
except oauth2client.client.AccessTokenRefreshError as e:
entityServiceNotApplicableWarning([u'Calendar', u'User'][api != u'calendar'], act_as, 0, 0)
print u'ERROR user %s: %s' % (act_as, e)
return handleOAuthTokenError(e, True)
return service
@@ -1195,6 +1205,45 @@ def buildGplusGAPIObject(user):
userEmail = convertUserUIDtoEmailAddress(user)
return (userEmail, buildGAPIServiceObject(u'plus', userEmail))
def doCheckServiceAccount(users):
for user in users:
all_scopes_pass = True
all_scopes = []
print u'User: %s' % (user)
for api, scopes in API_SCOPE_MAPPING.items():
for scope in scopes:
if scope in all_scopes:
continue # don't check same scope twice
all_scopes.append(scope)
all_scopes = sorted(all_scopes)
for scope in all_scopes:
try:
service = buildGAPIServiceObject(api, act_as=user, use_scopes=scope)
service._http.request.credentials.refresh(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL]))
result = u'PASS'
except oauth2client.client.HttpAccessTokenRefreshError:
result = u'FAIL'
all_scopes_pass = False
print u' Scope: {0:60} {1}'.format(scope, result)
service_account = service._http.request.credentials.serialization_data[u'client_id']
if all_scopes_pass:
print u'\nAll scopes passed!\nService account %s is fully authorized.' % service_account
else:
user_domain = user[user.find(u'@')+1:]
print u'''
ERROR: Some scopes failed! Please go to:
https://admin.google.com/%s/AdminHome?#OGX:ManageOauthClients
and grant Client name:
%s
Access to scopes:
%s\n''' % (user_domain, service_account, ','.join(all_scopes))
sys.exit(int(not all_scopes_pass))
def showReport():
def _adjustDate(errMsg):
@@ -6753,6 +6802,139 @@ def getUserAttributes(i, cd, updateCmd=False):
body[u'hashFunction'] = u'crypt'
return (body, admin_body)
def doCreateProject():
try:
login_hint = sys.argv[3]
except IndexError:
while True:
login_hint = raw_input(u'\nWhat is your G Suite admin email address? ')
if login_hint.find(u'@') == -1:
print u'Error: that is not a valid email address'
else:
break
from oauth2client.contrib.dictionary_storage import DictionaryStorage
project_id = u'gam-project'
for i in range(3):
project_id += u'-%s' % ''.join(random.choice(string.digits + string.ascii_lowercase) for i in range(3))
project_name = u'project:%s' % project_id
scope=u'https://www.googleapis.com/auth/cloud-platform'
client_id=u'297408095146-fug707qsjv4ikron0hugpevbrjhkmsk7.apps.googleusercontent.com'
client_secret=u'qM3dP8f_4qedwzWQE1VR4zzU'
flow = oauth2client.client.OAuth2WebServerFlow(client_id=client_id,
client_secret=client_secret, scope=scope, redirect_uri=oauth2client.client.OOB_CALLBACK_URN,
user_agent=GAM_INFO, access_type=u'online', response_type=u'code', login_hint=login_hint)
flags = cmd_flags(noLocalWebserver=GC_Values[GC_NO_BROWSER])
storage_dict = {}
storage = DictionaryStorage(storage_dict, u'credentials')
flags = cmd_flags(noLocalWebserver=GC_Values[GC_NO_BROWSER])
http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])
try:
credentials = oauth2client.tools.run_flow(flow=flow, storage=storage, flags=flags, http=http)
except httplib2.CertificateValidationUnsupported:
noPythonSSLExit()
credentials.user_agent = GAM_INFO
http = credentials.authorize(httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL],
cache=GC_Values[GC_CACHE_DIR]))
crm = googleapiclient.discovery.build(u'cloudresourcemanager', u'v1', http=http, cache_discovery=False)
body = {u'projectId': project_id, u'name': u'GAM Project'}
while True:
create_again = False
print u'Creating project "%s"...' % body[u'name']
create_operation = callGAPI(crm.projects(), u'create', body=body)
operation_name = create_operation[u'name']
time.sleep(5) # Google recommends always waiting at least 5 seconds
for i in range(1, 5):
print u'Checking project status...'
status = callGAPI(crm.operations(), u'get', name=operation_name)
if u'error' in status:
if u'message' in status[u'error'] and status[u'error'][u'message'].find(u'Callers must accept ToS') != -1:
print u'''Please go to:
https://console.developers.google.com
and accept the Terms of Service (ToS). As soon as you've accepted the ToS popup, you can return here and press enter.'''
raw_input()
create_again = True
break
else:
sys.exit(1)
if u'done' in status and status[u'done']:
break
sleep_time = i ** 2
print u'Project still being created. Sleeping %s seconds' % sleep_time
time.sleep(sleep_time)
if create_again:
continue
if not u'done' in status or not status[u'done']:
print u'Failed to create project: %s' % status
sys.exit(1)
elif u'error' in status:
print status[u'error']
sys.exit(2)
break
serveman = googleapiclient.discovery.build(u'servicemanagement', u'v1', http=http, cache_discovery=False)
apis = [u'admin-json.googleapis.com', u'appsactivity-json.googleapis.com', u'calendar-json.googleapis.com',
u'classroom.googleapis.com', u'drive', u'gmail-json.googleapis.com', u'groupssettings-json.googleapis.com',
u'licensing-json.googleapis.com', u'plus-json.googleapis.com', u'contacts-json.googleapis.com']
for api in apis:
print u' enabling API %s...' % api
enable_operation = callGAPI(serveman.services(), u'enable', serviceName=api, body={u'consumerId': project_name})
iam = googleapiclient.discovery.build(u'iam', u'v1', http=http, cache_discovery=False)
print u'Creating Service Account'
service_account = callGAPI(iam.projects().serviceAccounts(), u'create', name=u'projects/%s' % project_id,
body={u'accountId': project_id, u'serviceAccount': {u'displayName': u'GAM Project'}})
body = {u'privateKeyType': u'TYPE_GOOGLE_CREDENTIALS_FILE', u'keyAlgorithm': u'KEY_ALG_RSA_4096'}
key = callGAPI(iam.projects().serviceAccounts().keys(), u'create', name=service_account[u'name'], body=body)
oauth2service_data = base64.b64decode(key[u'privateKeyData'])
service_account_file = os.path.join(GM_Globals[GM_GAM_PATH], FN_OAUTH2SERVICE_JSON)
if os.path.isfile(service_account_file):
service_account_file = u'%s-%s' % (service_account_file, project_id)
writeFile(service_account_file, oauth2service_data, continueOnError=False)
console_credentials_url = u'https://console.developers.google.com/apis/credentials?project=%s' % project_id
print u'''Please go to:
%s
1. Click the blue "Create credentials" button. Choose "OAuth client ID".
2. Click the blue "Configure consent screen" button. Enter "GAM" for "Product name to show to users".
3. Leave other fields blank. Click "Save" button.
3. Choose "Other" and click the blue "Create" button.
4. Copy your "client ID" value.
''' % console_credentials_url
client_id = raw_input(u'Enter your Client ID: ')
print u'\nNow go back to your browser and copy your client secret.'
client_secret = raw_input(u'Enter your Client Secret: ')
cs_data = u'''{
"installed": {
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"client_id": "%s",
"client_secret": "%s",
"project_id": "%s",
"redirect_uris": [
"urn:ietf:wg:oauth:2.0:oob",
"http://localhost"
],
"token_uri": "https://accounts.google.com/o/oauth2/token"
}
}''' % (client_id, client_secret, project_id)
client_secrets_file = os.path.join(GM_Globals[GM_GAM_PATH], FN_CLIENT_SECRETS_JSON)
if os.path.isfile(client_secrets_file):
client_secrets_file = u'%s-%s' % (client_secrets_file, project_id)
writeFile(client_secrets_file, cs_data, continueOnError=False)
print u'''Almost there! Now please switch back to your browser and:
1. Click OK to close "OAuth client" popup if it's still open.
2. Click "Manage service accounts" on the right of the screen.
3. Click the 3 dots to the right of your service account.
4. Choose Edit.
5. Check the "Enable G Suite Domain-wide Delegation" box and click Save.
'''
raw_input(u'Press Enter when done...')
print u'That\'s it! Your GAM Project is created and ready to use.'
def doCreateUser():
cd = buildGAPIObject(u'directory')
body, admin_body = getUserAttributes(3, cd, updateCmd=False)
@@ -9760,7 +9942,7 @@ OAUTH2_MENU += '''
OAUTH2_CMDS = [u's', u'u', u'e', u'c']
MAXIMUM_SCOPES = 28
def doRequestOAuth():
def doRequestOAuth(login_hint=None):
def _checkMakeScopesList(scopes):
del scopes[:]
for i in range(num_scopes):
@@ -9780,10 +9962,13 @@ def doRequestOAuth():
scopes.insert(0, u'email') # Email Display Scope, always included
return (True, u'')
cs_file = os.path.join(GM_Globals[GM_GAM_PATH], FN_CLIENT_SECRETS_JSON)
MISSING_CLIENT_SECRETS_MESSAGE = u"""Please configure OAuth 2.0
To make GAM run you will need to populate the {0} file found at:
{1}
with information from the APIs Console <https://console.developers.google.com>.
See this site for instructions:
@@ -9791,6 +9976,26 @@ See this site for instructions:
""".format(FN_CLIENT_SECRETS_JSON, GC_Values[GC_CLIENT_SECRETS_JSON], GAM_WIKI_CREATE_CLIENT_SECRETS)
cs_data = readFile(cs_file, mode=u'rb', continueOnError=True, displayError=True, encoding=None)
if not cs_data:
systemErrorExit(14, MISSING_CLIENT_SECRETS_MESSAGE)
try:
cs_json = json.loads(cs_data)
client_id = cs_json[u'installed'][u'client_id']
client_secret = cs_json[u'installed'][u'client_secret']
except (ValueError, IndexError, KeyError):
print u'ERROR: the format of your client secrets file:\n\n%s\n\n is incorrect. Please recreate the file.'
sys.exit(3)
try:
login_hint = sys.argv[3]
except IndexError:
while True:
login_hint = raw_input(u'\nWhat is your G Suite admin email address? ')
if login_hint.find(u'@') == -1:
print u'Error: that is not a valid email address'
else:
break
num_scopes = len(OAUTH2_SCOPES)
menu = OAUTH2_MENU % tuple(range(num_scopes))
selected_scopes = []
@@ -9852,19 +10057,20 @@ See this site for instructions:
status, message = _checkMakeScopesList(scopes)
if status:
break
try:
FLOW = oauth2client.client.flow_from_clientsecrets(GC_Values[GC_CLIENT_SECRETS_JSON], scope=scopes)
except oauth2client.client.clientsecrets.InvalidClientSecretsError:
systemErrorExit(14, MISSING_CLIENT_SECRETS_MESSAGE)
flow = oauth2client.client.OAuth2WebServerFlow(client_id=client_id,
client_secret=client_secret, scope=scopes, redirect_uri=oauth2client.client.OOB_CALLBACK_URN,
user_agent=GAM_INFO, access_type=u'offline', response_type=u'code', login_hint=login_hint)
storage = oauth2client.file.Storage(GC_Values[GC_OAUTH2_TXT])
credentials = storage.get()
flags = cmd_flags(noLocalWebserver=GC_Values[GC_NO_BROWSER])
if credentials is None or credentials.invalid:
http = httplib2.Http(disable_ssl_certificate_validation=GC_Values[GC_NO_VERIFY_SSL])
try:
credentials = oauth2client.tools.run_flow(flow=FLOW, storage=storage, flags=flags, http=http)
credentials = oauth2client.tools.run_flow(flow=flow, storage=storage, flags=flags, http=http)
except httplib2.CertificateValidationUnsupported:
noPythonSSLExit()
else:
print u'It looks like you\'ve already authorized GAM. Refusing to overwrite existing file:\n\n%s' % GC_Values[GC_OAUTH2_TXT]
def batch_worker():
while True:
@@ -10043,6 +10249,8 @@ def ProcessGAMCommand(args):
doCreateAdmin()
elif argument in [u'guardianinvite', u'inviteguardian', u'guardian']:
doInviteGuardian()
elif argument in [u'project', u'apiproject']:
doCreateProject()
else:
print u'ERROR: %s is not a valid argument for "gam create"' % argument
sys.exit(2)
@@ -10554,6 +10762,10 @@ def ProcessGAMCommand(args):
else:
print u'ERROR: %s is not a valid argument for "gam <users> info"' % infoWhat
sys.exit(2)
elif command == u'check':
checkWhat = sys.argv[4].replace(u'_', '').lower()
if checkWhat == u'serviceaccount':
doCheckServiceAccount(users)
elif command == u'profile':
doProfile(users)
elif command == u'imap':

View File

@@ -44,6 +44,7 @@
Source="gam-64">
<Component Id="gam_exe" Guid="886abc07-73c5-4acc-9f71-58daf62aabc1">
<File Name="gam.exe" KeyPath="yes" />
<Environment Id="PATH" Name="PATH" Value="[INSTALLFOLDER]" Permanent="yes" Part="last" Action="set" System="yes" />
</Component>
<Component Id="license" Guid="7a15de2e-fb91-4d0a-b8bf-c8b19c68f569">
<File Name="LICENSE" KeyPath="yes" />

View File

@@ -8,9 +8,8 @@ for d in a.datas:
if 'pyconfig' in d[0]:
a.datas.remove(d)
break
a.datas += [('httplib2/cacerts.txt', 'httplib2\cacerts.txt', 'DATA')]
a.datas += [('httplib2/cacerts.txt', 'httplib2/cacerts.txt', 'DATA')]
a.datas += [('cloudprint-v2.json', 'cloudprint-v2.json', 'DATA')]
a.datas += [('email-audit-v1.json', 'email-audit-v1.json', 'DATA')]
a.datas += [('email-settings-v2.json', 'email-settings-v2.json', 'DATA')]
pyz = PYZ(a.pure)
exe = EXE(pyz,
@@ -21,5 +20,5 @@ exe = EXE(pyz,
name='gam',
debug=False,
strip=None,
upx=True,
upx=False,
console=True )

View File

@@ -3,7 +3,7 @@ rmdir /q /s build
rmdir /q /s dist
rm -rf gam-$1-macos.tar.xz
pyinstaller --clean -F --distpath=gam macos-gam.spec
/Library/Frameworks/Python.framework/Versions/2.7/bin/pyinstaller --clean -F --distpath=gam macos-gam.spec
cp LICENSE gam
cp whatsnew.txt gam

View File

@@ -8,9 +8,8 @@ for d in a.datas:
if 'pyconfig' in d[0]:
a.datas.remove(d)
break
a.datas += [('httplib2/cacerts.txt', 'httplib2\cacerts.txt', 'DATA')]
a.datas += [('httplib2/cacerts.txt', 'httplib2/cacerts.txt', 'DATA')]
a.datas += [('cloudprint-v2.json', 'cloudprint-v2.json', 'DATA')]
a.datas += [('email-audit-v1.json', 'email-audit-v1.json', 'DATA')]
a.datas += [('email-settings-v2.json', 'email-settings-v2.json', 'DATA')]
pyz = PYZ(a.pure)
exe = EXE(pyz,
@@ -21,5 +20,5 @@ exe = EXE(pyz,
name='gam',
debug=False,
strip=None,
upx=True,
upx=False,
console=True )

View File

@@ -11,7 +11,6 @@ for d in a.datas:
break
a.datas += [('httplib2/cacerts.txt', 'httplib2\cacerts.txt', 'DATA')]
a.datas += [('cloudprint-v2.json', 'cloudprint-v2.json', 'DATA')]
a.datas += [('email-audit-v1.json', 'email-audit-v1.json', 'DATA')]
a.datas += [('email-settings-v2.json', 'email-settings-v2.json', 'DATA')]
pyz = PYZ(a.pure)
exe = EXE(pyz,