Skip to content

Commit

Permalink
Improve auth setup experience with more self-contained explanations/l…
Browse files Browse the repository at this point in the history
…inks
  • Loading branch information
dbarnett committed Aug 27, 2024
1 parent 25ced11 commit 6767e33
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 42 deletions.
2 changes: 0 additions & 2 deletions gcalcli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
__program__ = 'gcalcli'
__version__ = 'v4.3.0'
__author__ = 'Eric Davis, Brian Hartvigsen, Joshua Crowgey'
__API_CLIENT_ID__ = '232867676714.apps.googleusercontent.com'
__API_CLIENT_SECRET__ = '3tZSxItw6_VnZMezQwC8lUqy'
4 changes: 2 additions & 2 deletions gcalcli/argparsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
from .printer import valid_color_name

PROGRAM_OPTIONS = {
'--client-id': {'default': gcalcli.__API_CLIENT_ID__,
'--client-id': {'default': None,
'type': str,
'help': 'API client_id'},
'--client-secret': {'default': gcalcli.__API_CLIENT_SECRET__,
'--client-secret': {'default': None,
'type': str,
'help': 'API client_secret'},
'--config-folder': {'default': None, 'type': str,
Expand Down
26 changes: 26 additions & 0 deletions gcalcli/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow


def authenticate(client_id: str, client_secret: str):
flow = InstalledAppFlow.from_client_config(
client_config={
"installed": {
"client_id": client_id,
"client_secret": client_secret,
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url":
"https://www.googleapis.com/oauth2/v1/certs",
"redirect_uris": ["http://localhost"],
}
},
scopes=["https://www.googleapis.com/auth/calendar"],
)
credentials = flow.run_local_server(open_browser=False)
return credentials


def refresh_if_expired(credentials) -> None:
if credentials.expired:
credentials.refresh(Request())
6 changes: 2 additions & 4 deletions gcalcli/deprecations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import functools
from typing import Any, Dict

import gcalcli

from .printer import Printer, valid_color_name

printer = Printer()
Expand Down Expand Up @@ -73,8 +71,8 @@ def __call__(self, parser, namespace, values, option_string=None):

OPTIONS: Dict[str, Dict[str, Any]] = {
'program': {
"--client_id": {'default': gcalcli.__API_CLIENT_ID__},
"--client_secret": {'default': gcalcli.__API_CLIENT_SECRET__},
"--client_id": {'default': None},
"--client_secret": {'default': None},
"--configFolder": {'default': None},
"--defaultCalendar": {'default': [], 'action': DeprecatedAppend}
},
Expand Down
80 changes: 46 additions & 34 deletions gcalcli/gcal.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
from dateutil.parser import parse
from dateutil.relativedelta import relativedelta
from dateutil.tz import tzlocal
from google_auth_oauthlib.flow import InstalledAppFlow # type: ignore
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google.auth.transport.requests import Request # type: ignore

from . import actions, ics, utils
from . import actions, auth, ics, utils
from ._types import Cache, CalendarListEntry, Event
from .actions import ACTIONS
from .conflicts import ShowConflicts
Expand Down Expand Up @@ -122,40 +120,54 @@ def _retry_with_backoff(self, method: googleapiclient.http.HttpRequest):
return None

def _google_auth(self):
if self.credentials:
return self.credentials

# Try loading cached credentials
if self.options['config_folder']:
oauth_filepath = os.path.expanduser(
'%s/oauth' % self.options['config_folder']
)
else:
oauth_filepath = os.path.expanduser('~/.gcalcli_oauth')
if os.path.exists(oauth_filepath):
with open(oauth_filepath, 'rb') as gcalcli_oauth:
self.credentials = pickle.load(gcalcli_oauth)

if not self.credentials:
if self.options['config_folder']:
oauth_filepath = os.path.expanduser(
'%s/oauth' % self.options['config_folder']
)
else:
oauth_filepath = os.path.expanduser('~/.gcalcli_oauth')
if os.path.exists(oauth_filepath):
with open(oauth_filepath, 'rb') as gcalcli_oauth:
credentials = pickle.load(gcalcli_oauth)
else:
flow = InstalledAppFlow.from_client_config(
client_config={
"installed": {
"client_id": self.options['client_id'],
"client_secret": self.options['client_secret'],
"auth_uri":
"https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url":
"https://www.googleapis.com/oauth2/v1/certs",
"redirect_uris": ["http://localhost"]
}
},
scopes=['https://www.googleapis.com/auth/calendar']
# No cached credentials, start auth flow
self.printer.msg(
'Not yet authenticated. Starting auth flow...\n', 'yellow')
self.printer.msg(
'NOTE: See https://github.com/insanum/gcalcli for '
'help/troubleshooting.\n')
missing_info = [opt for opt in ['client_id', 'client_secret']
if self.options.get(opt) is None]
if missing_info:
self.printer.msg(
f"You'll be asked for a {' and '.join(missing_info)} "
'that you should have set up for yourself in Google '
'dev console.\n'
)
credentials = flow.run_local_server(open_browser=False)
with open(oauth_filepath, 'wb') as gcalcli_oauth:
pickle.dump(credentials, gcalcli_oauth)

if credentials.expired:
credentials.refresh(Request())
client_id = self.options.get('client_id')
if client_id is None:
self.printer.msg('Client ID: ', 'magenta')
client_id = input()
client_secret = self.options.get('client_secret')
if client_secret is None:
self.printer.msg('Client Secret: ', 'magenta')
client_secret = input()
self.printer.msg(
'Now click the link below and follow directions to '
'authenticate.\n', 'yellow')
self.printer.msg(
'You will likely see a security warning page and need to '
'click "Advanced" and "Go to gcalcli (unsafe)" to proceed.\n')
self.credentials = auth.authenticate(client_id, client_secret)
with open(oauth_filepath, 'wb') as gcalcli_oauth:
pickle.dump(self.credentials, gcalcli_oauth)

self.credentials = credentials
auth.refresh_if_expired(self.credentials)
return self.credentials

def get_cal_service(self):
Expand Down

0 comments on commit 6767e33

Please sign in to comment.