-
-
Save dskecse/56db659bfefaa27820f9a2fb88bfe9bb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This file specifies files that are *not* uploaded to Google Cloud Platform | |
| # using gcloud. It follows the same syntax as .gitignore, with the addition of | |
| # "#!include" directives (which insert the entries of the given .gitignore-style | |
| # file at that point). | |
| # | |
| # For more information, run: | |
| # $ gcloud topic gcloudignore | |
| # | |
| .gcloudignore | |
| # If you would like to upload your .git directory, .gitignore file or files | |
| # from your .gitignore file, remove the corresponding line | |
| # below: | |
| .git | |
| .gitignore | |
| # Python pycache: | |
| __pycache__/ | |
| # Ignored by the build system | |
| /setup.cfg | |
| .venv |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| .venv/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| runtime: python37 | |
| service: default |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import flask | |
| import logging | |
| import sys | |
| import datetime | |
| import base64 | |
| import google.auth.transport.requests | |
| from google.auth import compute_engine | |
| from google.auth.iam import Signer | |
| from gumo.core import configure as core_configure | |
| from gumo.core import get_google_oauth_credential | |
| from gumo.storage.infrastructure import build_signed_url | |
| from gumo.storage.infrastructure import SignedURLFactory | |
| logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) | |
| logger = logging.getLogger(__name__) | |
| app = flask.Flask(__name__) | |
| core_configure( | |
| google_cloud_project='levii-playground-signed-url', | |
| google_cloud_location='us-central1', | |
| ) | |
| class AppEngineCredentials: | |
| _credentials = None | |
| @classmethod | |
| def fetch(cls): | |
| if cls._credentials is None: | |
| cls._credentials = compute_engine.Credentials() | |
| if not cls._credentials.valid or cls._credentials.service_account_email is None: | |
| request = google.auth.transport.requests.Request() | |
| cls._credentials.refresh(request=request) | |
| logger.debug(f'credential refreshed.') | |
| return cls._credentials | |
| @app.route('/') | |
| def hello(): | |
| return 'Hello' | |
| def storage_signed_url(bucket_name: str, blob_path: str): | |
| credentials = AppEngineCredentials.fetch() | |
| request = google.auth.transport.requests.Request() | |
| signer = Signer( | |
| request=request, | |
| credentials=credentials, | |
| service_account_email=credentials.service_account_email | |
| ) | |
| signer_email = credentials.service_account_email | |
| http_verb = 'GET' | |
| md5_digest = '' | |
| content_type = '' | |
| expiration = int((datetime.datetime.utcnow() + datetime.timedelta(days=1)).timestamp()) | |
| blob_path = blob_path if blob_path.startswith('/') else f'/{blob_path}' | |
| sign_info = [ | |
| http_verb, | |
| md5_digest, | |
| content_type, | |
| str(expiration), | |
| f'/{bucket_name}{blob_path}' | |
| ] | |
| string_to_sign = '\n'.join(sign_info) | |
| signature = signer.sign(string_to_sign.encode('ascii')) | |
| encoded_signature = base64.b64encode(signature).decode('ascii') | |
| escaped_signature = encoded_signature.replace('+', '%2B').replace('/', '%2F') | |
| base_url = f'https://storage.googleapis.com/{bucket_name}{blob_path}' | |
| params = '&'.join([ | |
| f'GoogleAccessId={signer_email}', | |
| f'Expires={expiration}', | |
| f'Signature={escaped_signature}', | |
| ]) | |
| return f'{base_url}?{params}' | |
| class ModifiedSignedURLFactory(SignedURLFactory): | |
| @classmethod | |
| def get_credential(cls): | |
| if cls._credential is None: | |
| cls._credential = get_google_oauth_credential() | |
| if not cls._credential.valid or cls._credential.service_account_email is None: | |
| request = google.auth.transport.requests.Request() | |
| cls._credential.refresh(request=request) | |
| return cls._credential | |
| def modified_build_signed_url( | |
| bucket_name: str, | |
| blob_path: str, | |
| http_verb: str = 'GET', | |
| md5_digest: str = '', | |
| content_type: str = '', | |
| expiration_seconds: int = 3600, | |
| ): | |
| return ModifiedSignedURLFactory( | |
| bucket_name=bucket_name, | |
| blob_path=blob_path, | |
| http_verb=http_verb, | |
| md5_digest=md5_digest, | |
| content_type=content_type, | |
| expiration_seconds=expiration_seconds, | |
| ).build() | |
| @app.route('/storage-signed-url') | |
| def signed_url(): | |
| mode = flask.request.args.get('mode', 'google') | |
| if mode == 'google': | |
| signed_url = storage_signed_url( | |
| bucket_name='levii-playground-signed-url', | |
| blob_path='testfile.txt' | |
| ) | |
| elif mode == 'gumo': | |
| signed_url = build_signed_url( | |
| bucket_name='levii-playground-signed-url', | |
| blob_path='testfile.txt' | |
| ) | |
| elif mode == 'gumo-modified': | |
| signed_url = modified_build_signed_url( | |
| bucket_name='levii-playground-signed-url', | |
| blob_path='testfile.txt' | |
| ) | |
| else: | |
| raise RuntimeError(f'Invalid parameters (mode={mode})') | |
| if 'bench' in flask.request.args: | |
| return 'ok' | |
| else: | |
| return signed_url | |
| if __name__ == '__main__': | |
| app.run(host='0.0.0.0', port=8080, debug=True) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| .PHONY: help | |
| help: | |
| @echo "[Usage] available sub commands:" | |
| @echo " * make deploy ... deploy to google app engine" | |
| .PHONY: deploy | |
| deploy: | |
| gcloud app deploy app.yaml --project=levii-playground-signed-url --quiet |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| google-cloud-storage | |
| flask | |
| requests | |
| gumo-storage |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # | |
| # This file is autogenerated by pip-compile | |
| # To update, run: | |
| # | |
| # pip-compile --output-file=requirements.txt requirements.in | |
| # | |
| cachetools==3.1.1 # via google-auth | |
| certifi==2019.3.9 # via requests | |
| chardet==3.0.4 # via requests | |
| click==7.0 # via flask | |
| flask==1.0.3 | |
| google-api-core==1.11.1 # via google-cloud-core | |
| google-api-python-client==1.7.9 # via gumo-core | |
| google-auth-httplib2==0.0.3 # via google-api-python-client | |
| google-auth==1.6.3 # via google-api-core, google-api-python-client, google-auth-httplib2, google-cloud-storage | |
| google-cloud-core==1.0.1 # via google-cloud-storage | |
| google-cloud-storage==1.16.1 | |
| google-resumable-media==0.3.2 # via google-cloud-storage | |
| googleapis-common-protos==1.6.0 # via google-api-core | |
| gumo-core==0.0.30 # via gumo-storage | |
| gumo-storage==0.0.5 | |
| httplib2==0.13.0 # via google-api-python-client, google-auth-httplib2 | |
| idna==2.8 # via requests | |
| injector==0.16.2 # via gumo-core | |
| itsdangerous==1.1.0 # via flask | |
| jinja2==2.10.1 # via flask | |
| markupsafe==1.1.1 # via jinja2 | |
| protobuf==3.8.0 # via google-api-core, googleapis-common-protos | |
| pyasn1-modules==0.2.5 # via google-auth | |
| pyasn1==0.4.5 # via pyasn1-modules, rsa | |
| pytz==2019.1 # via google-api-core | |
| pyyaml==5.1.1 # via gumo-core | |
| requests==2.22.0 | |
| rsa==4.0 # via google-auth | |
| six==1.12.0 # via google-api-core, google-api-python-client, google-auth, google-resumable-media, protobuf | |
| uritemplate==3.0.0 # via google-api-python-client | |
| urllib3==1.25.3 # via requests | |
| werkzeug==0.15.4 # via flask |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
More on
.gcloudignore:gcloud topic gcloudignoreTo display files that will be uploaded run: