diff --git a/.gitignore b/.gitignore index 548259c..51279e9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,9 @@ # General stuff .swp .cache +certificate/ calendarevents.json + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/login/app.py b/app.py similarity index 73% rename from login/app.py rename to app.py index bbb622b..1e7bb89 100644 --- a/login/app.py +++ b/app.py @@ -17,8 +17,8 @@ from oauthlib.oauth2 import WebApplicationClient import requests # Internal imports -from db import init_db_command -from user import User +from database.db import init_db_command +from database.user import User import caltojson @@ -28,7 +28,7 @@ import googleapiclient.discovery # Configuration -CLIENT_SECRETS_FILE = "client_secret.json" +CLIENT_SECRETS_FILE = "certificate/client_secret.json" # This OAuth 2.0 access scope allows for full read/write access to the # authenticated user's account and requires requests to use an SSL connection. @@ -186,71 +186,6 @@ def callback(): login_user(user) return flask.redirect(flask.url_for('index')) - ''' - # Get authorization code Google sent back to you - code = request.args.get("code") - # Find out what URL to hit to get tokens that allow you to ask for - # things on behalf of a user - google_provider_cfg = get_google_provider_cfg() - token_endpoint = google_provider_cfg["token_endpoint"] - - # Prepare and send a request to get tokens! Yay tokens! - token_url, headers, body = client.prepare_token_request( - token_endpoint, - authorization_response=request.url, - redirect_url=request.base_url, - code=code - ) - - print("asking for tokens") - - token_response = requests.post( - token_url, - headers=headers, - data=body, - auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET), - ) - - # Parse the tokens! - client.parse_request_body_response(json.dumps(token_response.json())) - - # Now that you have tokens (yay) let's find and hit the URL - # from Google that gives you the user's profile information, - # including their Google profile image and email - userinfo_endpoint = google_provider_cfg["userinfo_endpoint"] - uri, headers, body = client.add_token(userinfo_endpoint) - userinfo_response = requests.get(uri, headers=headers, data=body) - print(userinfo_response.json()) - - # You want to make sure their email is verified. - # The user authenticated with Google, authorized your - # app, and now you've verified their email through Google! - if userinfo_response.json().get("email_verified"): - unique_id = userinfo_response.json()["sub"] - users_email = userinfo_response.json()["email"] - picture = userinfo_response.json()["picture"] - users_name = userinfo_response.json()["given_name"] - else: - return "User email not available or not verified by Google.", 400 - - # Create a user in your db with the information provided - # by Google - user = User( - id_=unique_id, name=users_name, email=users_email, profile_pic=picture - ) - - # Doesn't exist? Add it to the database. - if not User.get(unique_id): - User.create(unique_id, users_name, users_email, picture) - - # Begin user session by logging the user in - login_user(user) - - # Send user back to homepage - return redirect(url_for("index")) - - ''' - @app.route("/logout") @login_required def logout(): @@ -265,8 +200,15 @@ def credentials_to_dict(credentials): 'client_secret': credentials.client_secret, 'scopes': credentials.scopes} + +@app.route("/userinfo/107971745944668140075/calendarevents.json") +def downloader(): + path = "/home/raphael/dev/website_ws/website/login/userinfo/107971745944668140075" + return flask.send_from_directory(path, "calendarevents.json") + if __name__ == "__main__": - app.run('192.168.68.103.xip.io', 1234, ssl_context="adhoc", debug=True) + context = ('certificate/xip.io.crt', 'certificate/xip.io.key')#certificate and key files + app.run('192.168.68.103.xip.io', 1234, ssl_context=context, debug=True) diff --git a/login/db.py b/database/db.py similarity index 81% rename from login/db.py rename to database/db.py index 60e4af5..d92ed8e 100644 --- a/login/db.py +++ b/database/db.py @@ -8,14 +8,14 @@ from flask.cli import with_appcontext def get_db(): if "db" not in g: g.db = sqlite3.connect( - "sqlite_db", detect_types=sqlite3.PARSE_DECLTYPES + "database/sqlite_db", detect_types=sqlite3.PARSE_DECLTYPES ) g.db.row_factory = sqlite3.Row return g.db def close_db(e=None): - db = g.pop("db", None) + db = g.pop("db/db", None) if db is not None: db.close() @@ -23,7 +23,7 @@ def close_db(e=None): def init_db(): db = get_db() - with current_app.open_resource("schema.sql") as f: + with current_app.open_resource("database/schema.sql") as f: db.executescript(f.read().decode("utf8")) @click.command("init-db") diff --git a/login/schema.sql b/database/schema.sql similarity index 100% rename from login/schema.sql rename to database/schema.sql diff --git a/login/sqlite_db b/database/sqlite_db similarity index 95% rename from login/sqlite_db rename to database/sqlite_db index 42d1c94..01e423b 100644 Binary files a/login/sqlite_db and b/database/sqlite_db differ diff --git a/login/user.py b/database/user.py similarity index 87% rename from login/user.py rename to database/user.py index e8165a5..539fb2e 100644 --- a/login/user.py +++ b/database/user.py @@ -1,6 +1,7 @@ from flask_login import UserMixin +from pathlib import Path -from db import get_db +from database.db import get_db class User(UserMixin): def __init__(self, id_, name, email, profile_pic): @@ -32,3 +33,6 @@ class User(UserMixin): (id_, name, email, profile_pic), ) db.commit() + + Path(f"userinfo/{id_}").mkdir(parents=True, exist_ok=True) + diff --git a/login/.app.py.swp b/login/.app.py.swp deleted file mode 100644 index 28cf93c..0000000 Binary files a/login/.app.py.swp and /dev/null differ diff --git a/login/client_secret.json b/login/client_secret.json deleted file mode 100644 index 2104b71..0000000 --- a/login/client_secret.json +++ /dev/null @@ -1 +0,0 @@ -{"web":{"client_id":"377787187748-shuvi4iq5bi4gdet6q3ioataimobs4lh.apps.googleusercontent.com","project_id":"calendarwatch-1584185874753","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","client_secret":"Hu_YWmKsVKUcLwyeINYzdKfZ","redirect_uris":["http://localhost:1234"],"javascript_origins":["http://raphael.maenle.net","https://raphael.maenle.net"]}} diff --git a/test1/client_secret.json b/test1/client_secret.json deleted file mode 100644 index 2104b71..0000000 --- a/test1/client_secret.json +++ /dev/null @@ -1 +0,0 @@ -{"web":{"client_id":"377787187748-shuvi4iq5bi4gdet6q3ioataimobs4lh.apps.googleusercontent.com","project_id":"calendarwatch-1584185874753","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","client_secret":"Hu_YWmKsVKUcLwyeINYzdKfZ","redirect_uris":["http://localhost:1234"],"javascript_origins":["http://raphael.maenle.net","https://raphael.maenle.net"]}} diff --git a/test1/index.html b/test1/index.html deleted file mode 100644 index 0aab441..0000000 --- a/test1/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - -
- - - - diff --git a/test1/index.js b/test1/index.js deleted file mode 100644 index f2e88d7..0000000 --- a/test1/index.js +++ /dev/null @@ -1,8 +0,0 @@ -const express = require('express') -const path = require('path') -const PORT = process.env.PORT || 1234 - -express() - .use(express.static(path.join(__dirname,'public'))) - .get('/', (req, res) => res.render('index')) - .listen(PORT, () => console.log(`Listening on ${ PORT }`)) diff --git a/test1/server.py b/test1/server.py deleted file mode 100644 index e43f9ed..0000000 --- a/test1/server.py +++ /dev/null @@ -1,193 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import flask -import requests - -import google.oauth2.credentials -import google_auth_oauthlib.flow -import googleapiclient.discovery - -# This variable specifies the name of a file that contains the OAuth 2.0 -# information for this application, including its client_id and client_secret. -CLIENT_SECRETS_FILE = "client_secret.json" - -# This OAuth 2.0 access scope allows for full read/write access to the -# authenticated user's account and requires requests to use an SSL connection. -SCOPES = ["https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://www.googleapis.com/auth/calendar.readonly", "openid"] -API_SERVICE_NAME = 'calendar' -API_VERSION = 'v3' - -app = flask.Flask(__name__) -# Note: A secret key is included in the sample so that it works. -# If you use this code in your application, replace this with a truly secret -# key. See https://flask.palletsprojects.com/quickstart/#sessions. -app.secret_key = 'N\x0cOZO\xca\x96b\xf0\\\xc7\x11\xbd(\x95\xe3' - - -class Calendar: - def __init__(self, summary_, calendarId_, color_): - self.summary = summary_ - self.calendarId = calendarId_ - self.color = color_ - -@app.route('/') -def index(): - return print_index_table() - - -@app.route('/test') -def test_api_request(): - if 'credentials' not in flask.session: - return flask.redirect('authorize') - - # Load credentials from the session. - credentials = google.oauth2.credentials.Credentials( - **flask.session['credentials']) - - service = googleapiclient.discovery.build( - API_SERVICE_NAME, API_VERSION, credentials=credentials) - - getCalendars(service) - - # Save credentials back to session in case access token was refreshed. - # ACTION ITEM: In a production app, you likely want to save these - # credentials in a persistent database instead. - flask.session['credentials'] = credentials_to_dict(credentials) - - return flask.jsonify("{}") - - -@app.route('/authorize') -def authorize(): - # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps. - flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( - CLIENT_SECRETS_FILE, scopes=SCOPES) - - # The URI created here must exactly match one of the authorized redirect URIs - # for the OAuth 2.0 client, which you configured in the API Console. If this - # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch' - # error. - flow.redirect_uri = flask.url_for('oauth2callback', _external=True) - - authorization_url, state = flow.authorization_url( - # Enable offline access so that you can refresh an access token without - # re-prompting the user for permission. Recommended for web server apps. - access_type='offline', - # Enable incremental authorization. Recommended as a best practice. - include_granted_scopes='true') - - # Store the state so the callback can verify the auth server response. - flask.session['state'] = state - - print("auth_url: " + authorization_url) - print("state: " + state) - - return flask.redirect(authorization_url) - - -@app.route('/oauth2callback') -def oauth2callback(): - # Specify the state when creating the flow in the callback so that it can - # verified in the authorization server response. - state = flask.session['state'] - - flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( - CLIENT_SECRETS_FILE, scopes=SCOPES, state=state) - flow.redirect_uri = flask.url_for('oauth2callback', _external=True) - - # Use the authorization server's response to fetch the OAuth 2.0 tokens. - authorization_response = flask.request.url - flow.fetch_token(authorization_response=authorization_response) - - # Store credentials in the session. - # ACTION ITEM: In a production app, you likely want to save these - # credentials in a persistent database instead. - credentials = flow.credentials - flask.session['credentials'] = credentials_to_dict(credentials) - print("credentials: ") - print(credentials_to_dict(credentials)) - - return flask.redirect(flask.url_for('test_api_request')) - - -@app.route('/revoke') -def revoke(): - if 'credentials' not in flask.session: - return ('You need to authorize before ' + - 'testing the code to revoke credentials.') - - credentials = google.oauth2.credentials.Credentials( - **flask.session['credentials']) - - revoke = requests.post('https://oauth2.googleapis.com/revoke', - params={'token': credentials.token}, - headers = {'content-type': 'application/x-www-form-urlencoded'}) - - status_code = getattr(revoke, 'status_code') - if status_code == 200: - return('Credentials successfully revoked.' + print_index_table()) - else: - return('An error occurred.' + print_index_table()) - - -@app.route('/clear') -def clear_credentials(): - if 'credentials' in flask.session: - del flask.session['credentials'] - return ('Credentials have been cleared.

' + - print_index_table()) - - -def credentials_to_dict(credentials): - return {'token': credentials.token, - 'refresh_token': credentials.refresh_token, - 'token_uri': credentials.token_uri, - 'client_id': credentials.client_id, - 'client_secret': credentials.client_secret, - 'scopes': credentials.scopes} - -def print_index_table(): - return ('' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
Test an API requestSubmit an API request and see a formatted JSON response. ' + - ' Go through the authorization flow if there are no stored ' + - ' credentials for the user.
Test the auth flow directlyGo directly to the authorization flow. If there are stored ' + - ' credentials, you still might not be prompted to reauthorize ' + - ' the application.
Revoke current credentialsRevoke the access token associated with the current user ' + - ' session. After revoking credentials, if you go to the test ' + - ' page, you should see an invalid_grant error.' + - '
Clear Flask session credentialsClear the access token currently stored in the user session. ' + - ' After clearing the token, if you test the ' + - ' API request again, you should go back to the auth flow.' + - '
') - -def getCalendars(service): - page_token = None - calendars = [] - while True: - calendar_list = service.calendarList().list(pageToken=page_token).execute() - for calendar in calendar_list['items']: - calendars.append(Calendar(calendar['summary'], calendar['id'], calendar['colorId'])) - page_token = calendar_list.get('nextPageToken') - if not page_token: - break - - print(calendars) - - -if __name__ == '__main__': - # When running locally, disable OAuthlib's HTTPs verification. - # ACTION ITEM for developers: - # When running in production *do not* leave this option enabled. - os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1' - - # Specify a hostname and port that are set as a valid redirect URI - # for your API project in the Google API Console. - app.run('192.168.68.103.xip.io', 1234 , debug=True) \ No newline at end of file diff --git a/test1/website.py b/test1/website.py deleted file mode 100644 index 5cbf26c..0000000 --- a/test1/website.py +++ /dev/null @@ -1,105 +0,0 @@ -from google.oauth2 import id_token -from google.auth.transport import requests - -import pickle -import os.path -from googleapiclient.discovery import build - -from http.server import HTTPServer, SimpleHTTPRequestHandler, BaseHTTPRequestHandler -import socketserver -import logging -import json - -# some_file.py -import sys -# insert at 1, 0 is the script path (or '' in REPL) -sys.path.insert(1, '../calenderwatch_server/') - - -Handler = SimpleHTTPRequestHandler - -class S(BaseHTTPRequestHandler): - def _set_headers(self): - self.send_response(200) - self.send_header('Content-type', 'text/html') - self.end_headers() - - def do_GET(self): - self._set_headers() - f = open("index.html", "r") - self.wfile.write(f.read().encode('utf-8')) - - def do_HEAD(self): - self._set_headers() - - def do_POST(self): - self._set_headers() - print("in post method") - self.data_string = self.rfile.read(int(self.headers['Content-Length'])) - print('checking client id') - if checkClientId(self.data_string): - getApiAuth(self.data_string) - self.send_response(200) - self.end_headers() - self.wfile.write("Hello".encode('utf-8')) - return - -def run(server_class=HTTPServer, handler_class=S, port=1234): - logging.basicConfig(level=logging.INFO) - server_address = ('', port) - with socketserver.TCPServer(("", port), handler_class) as httpd: - print("serving at port", port) - httpd.serve_forever() - - -# (Receive token by HTTPS POST) -def checkClientId(token): - try: - - with open('client_secret.json', 'r') as json_file: - clientSecret = json.load(json_file) - CLIENT_ID = clientSecret["web"]["client_id"] - # Specify the CLIENT_ID of the app that accesses the backend: - idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID) - - # Or, if multiple clients access the backend server: - # idinfo = id_token.verify_oauth2_token(token, requests.Request()) - # if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]: - # raise ValueError('Could not verify audience.') - - if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']: - raise ValueError('Wrong issuer.') - - # If auth request is from a G Suite domain: - # if idinfo['hd'] != GSUITE_DOMAIN_NAME: - # raise ValueError('Wrong hosted domain.') - - # ID token is valid. Get the user's Google Account ID from the decoded token. - userid = idinfo['sub'] - print(f"valid user id: {userid}") - return True - except ValueError: - # ID token is invalid - print('invalid token') - return False - - -def getApiAuth(token): - - with open('client_secret.json', 'r') as json_file: - clientSecret = json.load(json_file) - CLIENT_ID = clientSecret["web"]["client_id"] - # Specify the CLIENT_ID of the app that accesses the backend: - idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID) - - # creds = pickle.load(idinfo) - - service = build('calendar', 'v3', credentials=idinfo) - -if __name__ == '__main__': - from sys import argv - - if len(argv) == 2: - run(port=int(argv[1])) - else: - run()