Skip to content

Commit

Permalink
auth flow: reintroduce --noauth_local_server arg to provide port forw…
Browse files Browse the repository at this point in the history
…arding instrs
  • Loading branch information
dbarnett committed Sep 11, 2024
1 parent fce7fc3 commit df616d8
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 73 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
v4.5.0
* Drop support for python <3.10
* Respect locally-installed certificates (ajkessel)
* Re-add a `--noauth_local_server` to provide instructions for authenticating
from a remote system using port forwarding

v4.4.0
* Fix lots of bugs by switching from deprecated oauth2client to
google_auth_oauthlib
Expand Down
61 changes: 33 additions & 28 deletions docs/man1/gcalcli.1
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,65 @@ Additionally, gcalcli can be used as a reminder service and execute any
application you want when an event is coming up.
.SH USAGE

gcalcli [-h]
[--version] [--default-calendar DEFAULT_CALENDAR]
[--calendar CALENDAR] [--refresh] [--client-id CLIENT_ID]
[--conky] [--nocache] [--locale LOCALE] [--noincluderc]
[--lineart {fancy,unicode,ascii}]
[--config-folder CONFIG_FOLDER] [--nocolor]
[--client-secret CLIENT_SECRET]
{list,search,edit,delete,agenda,calw,calm,quick,add,import,remind}
...
usage: gcalcli [-h] [--version] [--client-id CLIENT_ID] [--client-secret CLIENT_SECRET]
[--noauth_local_server] [--config-folder CONFIG_FOLDER] [--noincluderc]
[--calendar CALENDAR] [--default-calendar DEFAULTCALENDAR] [--locale LOCALE] [--refresh]
[--nocache] [--conky] [--nocolor] [--lineart {fancy,unicode,ascii}]
{list,search,edit,delete,agenda,agendaupdate,updates,conflicts,calw,calm,quick,add,import,remind}
...

Google Calendar Command Line Interface

Positional arguments:
{list,search,edit,delete,agenda,updates,conflicts,calw,calm,quick,add,import,remind}
Invoking a subcommand with --help prints subcommand
usage.
positional arguments:
{list,search,edit,delete,agenda,agendaupdate,updates,conflicts,calw,calm,quick,add,import,remind}
Invoking a subcommand with --help prints subcommand usage.
list list available calendars
search search for events within an optional time period
edit edit calendar events
delete delete events from the calendar
agenda get an agenda for a time period
updates get updates since a datetime for a time period
conflicts find conflicts between events matching search term
agendaupdate update calendar from agenda TSV file
updates get updates since a datetime for a time period (defaults to through end of current
month)
conflicts find event conflicts
calw get a week-based agenda in calendar format
calm get a month agenda in calendar format
quick quick-add an event to a calendar
add add a detailed event to the calendar
import import an ics/vcal file to a calendar
remind execute command if event occurs within <mins> time

Optional arguments:
options:
-h, --help show this help message and exit
--version show program's version number and exit
--client-id CLIENT_ID
API client_id (default:
232867676714.apps.googleusercontent.com)
--client-secret CLIENT_SECRET
API client_secret (default: 3tZSxItw6_VnZMezQwC8lUqy)
--noauth_local_server
Provide instructions for authenticating from a remote system using port
forwarding. Note: Previously this option invoked an "Out-Of-Band" variant of the
auth flow, but that deprecated mechanism is no longer supported. (default: True)
--config-folder CONFIG_FOLDER
Optional directory to load/store all configuration
information (default: None)
--noincluderc Whether to include ~/.gcalclirc when using
configFolder (default: True)
--calendar CALENDAR Which calendars to use (default: [])
--default-calendar DEFAULT_CALENDAR
Optional default calendar to use if no --calendar
options are given (default: [])
--calendar CALENDAR Which calendars to use (default: [])
--locale LOCALE System locale (default: )
--refresh Delete and refresh cached data (default: False)
--client-id CLIENT_ID
API client_id (default:
232867676714.apps.googleusercontent.com)
--conky Use Conky color codes (default: False)
--nocache Execute command without using cache (default: True)
--locale LOCALE System locale (default: )
--noincluderc Whether to include ~/.gcalclirc when using
configFolder (default: True)
--lineart {fancy,unicode,ascii}
Choose line art style for calendars: "fancy": for
VTcodes, "unicode" for Unicode box drawing characters,
"ascii" for old-school plusses, hyphens and pipes.
(default: fancy)
--config-folder CONFIG_FOLDER
Optional directory to load/store all configuration
information (default: None)
--nocolor Enable/Disable all color output (default: True)
--client-secret CLIENT_SECRET
API client_secret (default: 3tZSxItw6_VnZMezQwC8lUqy)


.SH DIAGNOSTICS
Expand Down
117 changes: 74 additions & 43 deletions gcalcli/argparsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,80 @@
from .printer import valid_color_name

PROGRAM_OPTIONS = {
'--client-id': {'default': None,
'type': str,
'help': 'API client_id'},
'--client-secret': {'default': None,
'type': str,
'help': 'API client_secret'},
'--config-folder': {'default': None, 'type': str,
'help': 'Optional directory to load/store all ' +
'configuration information'},
'--noincluderc': {'action': 'store_false',
'dest': 'includeRc',
'help': 'Whether to include ~/.gcalclirc when ' +
'using configFolder'},
'--calendar': {'default': [], 'type': str, 'action': 'append',
'help': 'Which calendars to use, in the format '
'"CalendarName" or "CalendarName#color", where '
'the #color suffix is the name of a valid ANSI '
'color (such as "brightblue"). This option may '
'be called multiple times to display '
'additional calendars.'},
'--default-calendar': {'default': [], 'type': str, 'action': 'append',
'dest': 'defaultCalendar',
'help': 'Optional default calendar to use if ' +
'no --calendar options are given'},
'--locale': {'default': '', 'type': str, 'help': 'System locale'},
'--refresh': {'action': 'store_true', 'dest': 'refresh_cache',
'default': False,
'help': 'Delete and refresh cached data'},
'--nocache': {'action': 'store_false', 'dest': 'use_cache',
'default': True,
'help': 'Execute command without using cache'},
'--conky': {'action': 'store_true', 'default': False,
'help': 'Use Conky color codes'},
'--nocolor': {'action': 'store_false', 'default': True,
'dest': 'color',
'help': 'Enable/Disable all color output'},
'--lineart': {'default': 'fancy',
'choices': ['fancy', 'unicode', 'ascii'],
'help': 'Choose line art style for calendars: ' +
'"fancy": for VTcodes, "unicode" for ' +
'Unicode box drawing characters, "ascii" ' +
'for old-school plusses, hyphens and pipes.'},
}
'--client-id': {'default': None, 'type': str, 'help': 'API client_id'},
'--client-secret': {
'default': None,
'type': str,
'help': 'API client_secret',
},
'--noauth_local_server': {
'action': 'store_false',
'dest': 'auth_local_server',
'help': 'Provide instructions for authenticating from a remote system '
'using port forwarding.\nNote: Previously this option invoked an '
'"Out-Of-Band" variant of the auth flow, but that deprecated mechanism '
'is no longer supported.',
},
'--config-folder': {
'default': None,
'type': str,
'help': 'Optional directory to load/store all configuration '
'information',
},
'--noincluderc': {
'action': 'store_false',
'dest': 'includeRc',
'help': 'Whether to include ~/.gcalclirc when using configFolder',
},
'--calendar': {
'default': [],
'type': str,
'action': 'append',
'help': 'Which calendars to use, in the format "CalendarName" or '
'"CalendarName#color", where the #color suffix is the name of a valid '
'ANSI color (such as "brightblue"). This option may be called multiple '
'times to display additional calendars.',
},
'--default-calendar': {
'default': [],
'type': str,
'action': 'append',
'dest': 'defaultCalendar',
'help': 'Optional default calendar to use if no --calendar options are '
'given',
},
'--locale': {'default': '', 'type': str, 'help': 'System locale'},
'--refresh': {
'action': 'store_true',
'dest': 'refresh_cache',
'default': False,
'help': 'Delete and refresh cached data',
},
'--nocache': {
'action': 'store_false',
'dest': 'use_cache',
'default': True,
'help': 'Execute command without using cache',
},
'--conky': {
'action': 'store_true',
'default': False,
'help': 'Use Conky color codes',
},
'--nocolor': {
'action': 'store_false',
'default': True,
'dest': 'color',
'help': 'Enable/Disable all color output',
},
'--lineart': {
'default': 'fancy',
'choices': ['fancy', 'unicode', 'ascii'],
'help': 'Choose line art style for calendars: "fancy": for VTcodes, '
'"unicode" for Unicode box drawing characters, "ascii" for old-school '
'plusses, hyphens and pipes.',
},
}


class DetailsAction(argparse._AppendAction):
Expand Down
27 changes: 26 additions & 1 deletion gcalcli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from google.oauth2.credentials import Credentials
from gcalcli.printer import Printer


def authenticate(client_id: str, client_secret: str):
def authenticate(
client_id: str, client_secret: str, printer: Printer, local: bool
):
flow = InstalledAppFlow.from_client_config(
client_config={
"installed": {
Expand All @@ -19,16 +22,38 @@ def authenticate(client_id: str, client_secret: str):
},
scopes=["https://www.googleapis.com/auth/calendar"],
)
if not local:
printer.msg(
'Note: Behavior of the `--noauth-local-server` option has changed! '
'Starting local server, but providing instructions for connecting '
'to it remotely...\n'
)
credentials = None
attempt_num = 0
# Retry up to 5 attempts with different random ports.
while credentials is None:
port = _free_local_port()
if not local:
printer.msg('Option 1 (outbound):\n', 'yellow')
printer.msg(
' To establish a connection from this system to a remote '
'host, execute a command like: `ssh username@host -L '
f'{port}:localhost:{port} BROWSER=open $BROWSER '
"'https://the-url-below'`\n",
)
printer.msg('Option 2 (outbound):\n', 'yellow')
printer.msg(
' To establish a connection from a remote host to this '
'system, execute a command from remote host like: '
f'`ssh username@host -fN -R {port}:localhost:{port} ; '
"BROWSER=open $BROWSER https://the-url-below'`\n\n",
)
try:
credentials = flow.run_local_server(open_browser=False, port=port)
except OSError as e:
if e.errno == 98 and attempt_num < 4:
# Will get retried with a different port.
printer.msg(f'Port {port} in use, trying another port...')
attempt_num += 1
else:
raise
Expand Down
7 changes: 6 additions & 1 deletion gcalcli/gcal.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,12 @@ def _google_auth(self):
'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)
self.credentials = auth.authenticate(
client_id,
client_secret,
printer=self.printer,
local=self.options['auth_local_server'],
)
with open(oauth_filepath, 'wb') as gcalcli_oauth:
pickle.dump(self.credentials, gcalcli_oauth)

Expand Down

0 comments on commit df616d8

Please sign in to comment.