mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-12 05:42:59 +00:00
Update calendar registration to use modern OAuth flow with local server callback
This commit is contained in:
@@ -5,6 +5,11 @@ from google_auth_oauthlib.flow import InstalledAppFlow
|
|||||||
from google.oauth2.credentials import Credentials
|
from google.oauth2.credentials import Credentials
|
||||||
from google.auth.transport.requests import Request
|
from google.auth.transport.requests import Request
|
||||||
import pickle
|
import pickle
|
||||||
|
import webbrowser
|
||||||
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||||
|
import threading
|
||||||
|
import urllib.parse
|
||||||
|
import socket
|
||||||
|
|
||||||
# If modifying these scopes, delete the file token.pickle.
|
# If modifying these scopes, delete the file token.pickle.
|
||||||
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
|
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
|
||||||
@@ -18,6 +23,32 @@ def save_credentials(creds, token_path):
|
|||||||
with open(token_path, 'wb') as token:
|
with open(token_path, 'wb') as token:
|
||||||
pickle.dump(creds, token)
|
pickle.dump(creds, token)
|
||||||
|
|
||||||
|
class OAuthHandler(BaseHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
# Parse the query parameters
|
||||||
|
query_components = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
|
||||||
|
|
||||||
|
if 'code' in query_components:
|
||||||
|
# Store the authorization code
|
||||||
|
self.server.auth_code = query_components['code'][0]
|
||||||
|
|
||||||
|
# Send success response to browser
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'text/html')
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"Authorization successful! You can close this window.")
|
||||||
|
else:
|
||||||
|
# Send error response
|
||||||
|
self.send_response(400)
|
||||||
|
self.send_header('Content-type', 'text/html')
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(b"Authorization failed! Please try again.")
|
||||||
|
|
||||||
|
def get_free_port():
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||||
|
s.bind(('', 0))
|
||||||
|
return s.getsockname()[1]
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
config = load_config()
|
config = load_config()
|
||||||
calendar_config = config.get('calendar', {})
|
calendar_config = config.get('calendar', {})
|
||||||
@@ -41,29 +72,44 @@ def main():
|
|||||||
print("1. Go to https://console.cloud.google.com")
|
print("1. Go to https://console.cloud.google.com")
|
||||||
print("2. Create a project or select existing project")
|
print("2. Create a project or select existing project")
|
||||||
print("3. Enable the Google Calendar API")
|
print("3. Enable the Google Calendar API")
|
||||||
print("4. Configure the OAuth consent screen (select TV and Limited Input Device)")
|
print("4. Configure the OAuth consent screen")
|
||||||
print("5. Create OAuth 2.0 credentials")
|
print("5. Create OAuth 2.0 credentials (Desktop application)")
|
||||||
print("6. Download the credentials and save as credentials.json")
|
print("6. Download the credentials and save as credentials.json")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Get a free port for the local server
|
||||||
|
port = get_free_port()
|
||||||
|
redirect_uri = f'http://localhost:{port}'
|
||||||
|
|
||||||
# Create the flow using the client secrets file from the Google API Console
|
# Create the flow using the client secrets file from the Google API Console
|
||||||
flow = InstalledAppFlow.from_client_secrets_file(
|
flow = InstalledAppFlow.from_client_secrets_file(
|
||||||
creds_file, SCOPES,
|
creds_file, SCOPES,
|
||||||
# Specify TV and Limited Input Device flow
|
redirect_uri=redirect_uri
|
||||||
redirect_uri='urn:ietf:wg:oauth:2.0:oob'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Start local server to receive the OAuth callback
|
||||||
|
server = HTTPServer(('localhost', port), OAuthHandler)
|
||||||
|
server.auth_code = None
|
||||||
|
server_thread = threading.Thread(target=server.serve_forever)
|
||||||
|
server_thread.daemon = True
|
||||||
|
server_thread.start()
|
||||||
|
|
||||||
# Generate URL for authorization
|
# Generate URL for authorization
|
||||||
auth_url, _ = flow.authorization_url(prompt='consent')
|
auth_url, _ = flow.authorization_url(prompt='consent')
|
||||||
|
|
||||||
print("\nPlease visit this URL to authorize this application:")
|
print("\nOpening your browser to authorize this application...")
|
||||||
print(auth_url)
|
webbrowser.open(auth_url)
|
||||||
print("\nAfter authorizing, you will receive a code. Enter that code below:")
|
|
||||||
|
|
||||||
code = input("Enter the authorization code: ")
|
print("\nWaiting for authorization...")
|
||||||
|
while server.auth_code is None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Stop the server
|
||||||
|
server.shutdown()
|
||||||
|
server.server_close()
|
||||||
|
|
||||||
# Exchange the authorization code for credentials
|
# Exchange the authorization code for credentials
|
||||||
flow.fetch_token(code=code)
|
flow.fetch_token(code=server.auth_code)
|
||||||
creds = flow.credentials
|
creds = flow.credentials
|
||||||
|
|
||||||
# Save the credentials
|
# Save the credentials
|
||||||
|
|||||||
Reference in New Issue
Block a user