From 7d1dfa1d0e2bb28cc99591f448d359e5d6e4482c Mon Sep 17 00:00:00 2001 From: richard-dds Date: Fri, 16 Aug 2019 16:06:17 -0400 Subject: [PATCH 01/13] Get presigned upload token via ajax request --- atst/domain/auth.py | 1 + atst/routes/__init__.py | 9 +++++++++ atst/routes/task_orders/new.py | 4 +--- js/components/upload_input.js | 21 +++++++++------------ js/lib/upload.js | 8 +++++--- templates/components/upload_input.html | 2 -- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/atst/domain/auth.py b/atst/domain/auth.py index 0f99af09..0f216c5f 100644 --- a/atst/domain/auth.py +++ b/atst/domain/auth.py @@ -13,6 +13,7 @@ UNPROTECTED_ROUTES = [ "atst.helpdocs", "static", "atst.about", + "atst.upload_token", ] diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index eaa447be..eba02c3e 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -9,6 +9,7 @@ from flask import ( request, make_response, current_app as app, + jsonify, ) from jinja2.exceptions import TemplateNotFound @@ -41,6 +42,14 @@ def root(): return render_template("login.html", redirect_url=redirect_url) +@bp.route("/upload-token") +def upload_token(): + (token, object_name) = app.csp.files.get_token() + render_args = {"token": token, "objectName": object_name} + + return jsonify(render_args) + + @bp.route("/help") @bp.route("/help/") def helpdocs(doc=None): diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index aca1c543..0bb14e9e 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -17,9 +17,7 @@ from atst.utils.flash import formatted_flash as flash def render_task_orders_edit(template, portfolio_id=None, task_order_id=None, form=None): - (token, object_name) = current_app.csp.files.get_token() - render_args = {"token": token, "object_name": object_name} - + render_args = {} if task_order_id: task_order = TaskOrders.get(task_order_id) portfolio_id = task_order.portfolio_id diff --git a/js/components/upload_input.js b/js/components/upload_input.js index edf01450..530d3e59 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -20,12 +20,6 @@ export default { props: { name: String, - token: { - type: Object, - }, - objectName: { - type: String, - }, initialData: { type: String, }, @@ -52,8 +46,7 @@ export default { } }, - created: function() { - this.uploader = buildUploader(this.token) + created: async function() { emitEvent('field-mount', this, { optional: this.optional, name: this.name, @@ -71,13 +64,12 @@ export default { return } - const response = await this.uploader.upload(file, this.objectName) - + const uploader = await this.getUploader() + const response = await uploader.upload(file, this.objectName) if (response.ok) { this.attachment = e.target.value this.$refs.attachmentFilename.value = file.name - this.$refs.attachmentObjectName.value = this.objectName - this.$refs.attachmentInput.disabled = true + this.$refs.attachmentObjectName.value = response.objectName } else { this.uploadError = true } @@ -111,6 +103,11 @@ export default { this.uploadError = false this.sizeError = false }, + getUploader: async function() { + return fetch('/upload-token') + .then(response => response.json()) + .then(({ token }) => buildUploader(token)) + }, }, computed: { diff --git a/js/lib/upload.js b/js/lib/upload.js index ff85ab4a..33cf7c5c 100644 --- a/js/lib/upload.js +++ b/js/lib/upload.js @@ -34,7 +34,7 @@ class AzureUploader { if (err) { resolve({ ok: false }) } else { - resolve({ ok: true }) + resolve({ ok: true, objectName }) } } ) @@ -57,10 +57,12 @@ class AwsUploader { form.append('file', file) form.set('x-amz-meta-filename', file.name) - return fetch(this.presignedPost.url, { + const response = await fetch(this.presignedPost.url, { method: 'POST', body: form, }) + + return { ok: response.ok, objectName } } } @@ -70,7 +72,7 @@ class MockUploader { } async upload(file, objectName) { - return Promise.resolve({ ok: true }) + return Promise.resolve({ ok: true, objectName }) } } diff --git a/templates/components/upload_input.html b/templates/components/upload_input.html index a261ea21..f78b6b31 100644 --- a/templates/components/upload_input.html +++ b/templates/components/upload_input.html @@ -11,8 +11,6 @@ v-bind:watch='{{ watch | string | lower }}' name='{{ field.name }}' :optional='false' - v-bind:token='{{ token | tojson }}' - v-bind:object-name='"{{ object_name | string }}"' >
From 27e0e1670741877d9591cbd9ad692775474c6da2 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 19 Aug 2019 16:28:49 -0400 Subject: [PATCH 02/13] Require auth on upload-token --- atst/domain/auth.py | 1 - atst/routes/task_orders/new.py | 1 - js/components/upload_input.js | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/atst/domain/auth.py b/atst/domain/auth.py index 0f216c5f..0f99af09 100644 --- a/atst/domain/auth.py +++ b/atst/domain/auth.py @@ -13,7 +13,6 @@ UNPROTECTED_ROUTES = [ "atst.helpdocs", "static", "atst.about", - "atst.upload_token", ] diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index 0bb14e9e..2ea48a41 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -4,7 +4,6 @@ from flask import ( render_template, request as http_request, url_for, - current_app, ) from . import task_orders_bp diff --git a/js/components/upload_input.js b/js/components/upload_input.js index 530d3e59..3f443353 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -104,7 +104,7 @@ export default { this.sizeError = false }, getUploader: async function() { - return fetch('/upload-token') + return fetch('/upload-token', { credentials: "include" }) .then(response => response.json()) .then(({ token }) => buildUploader(token)) }, From de090a319b263f109ecdb3652618e4ddfe7e4f8d Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 19 Aug 2019 16:30:23 -0400 Subject: [PATCH 03/13] Pass objectName into upload constructor --- js/components/upload_input.js | 2 +- js/lib/upload.js | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/js/components/upload_input.js b/js/components/upload_input.js index 3f443353..5254ca19 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -106,7 +106,7 @@ export default { getUploader: async function() { return fetch('/upload-token', { credentials: "include" }) .then(response => response.json()) - .then(({ token }) => buildUploader(token)) + .then(({ token, objectName }) => buildUploader(token, objectName)) }, }, diff --git a/js/lib/upload.js b/js/lib/upload.js index 33cf7c5c..a9d06b07 100644 --- a/js/lib/upload.js +++ b/js/lib/upload.js @@ -2,13 +2,14 @@ import Azure from 'azure-storage' import 'whatwg-fetch' class AzureUploader { - constructor(accountName, containerName, sasToken) { + constructor(accountName, containerName, sasToken, objectName) { this.accountName = accountName this.containerName = containerName this.sasToken = sasToken.token + this.objectName = objectName } - async upload(file, objectName) { + async upload(file) { const blobService = Azure.createBlobServiceWithSas( `https://${this.accountName}.blob.core.windows.net`, this.sasToken @@ -27,14 +28,14 @@ class AzureUploader { fileReader.addEventListener('load', f => { blobService.createBlockBlobFromText( this.containerName, - `${objectName}`, + `${this.objectName}`, f.target.result, options, function(err, result) { if (err) { resolve({ ok: false }) } else { - resolve({ ok: true, objectName }) + resolve({ ok: true, objectName: this.objectName }) } } ) @@ -45,11 +46,12 @@ class AzureUploader { } class AwsUploader { - constructor(presignedPost) { + constructor(presignedPost, objectName) { this.presignedPost = presignedPost + this.objectName = objectName } - async upload(file, objectName) { + async upload(file) { const form = new FormData() Object.entries(this.presignedPost.fields).forEach(([k, v]) => { form.append(k, v) @@ -62,31 +64,34 @@ class AwsUploader { body: form, }) - return { ok: response.ok, objectName } + return { ok: response.ok, objectName: this.objectName } } } class MockUploader { - constructor(token) { + constructor(token, objectName) { this.token = token + this.objectName = objectName + console.log("built MockUploader") } async upload(file, objectName) { - return Promise.resolve({ ok: true, objectName }) + return Promise.resolve({ ok: true, objectName: this.objectName }) } } -export const buildUploader = token => { +export const buildUploader = (token, objectName) => { const cloudProvider = process.env.CLOUD_PROVIDER || 'mock' if (cloudProvider === 'aws') { - return new AwsUploader(token) + return new AwsUploader(token, objectName) } else if (cloudProvider === 'azure') { return new AzureUploader( process.env.AZURE_ACCOUNT_NAME, process.env.AZURE_CONTAINER_NAME, - token + token, + objectName ) } else { - return new MockUploader(token) + return new MockUploader(token, objectName) } } From 85ba61b97bd9225a645a5eb83231b0aba9743f57 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 26 Aug 2019 10:10:49 -0400 Subject: [PATCH 04/13] Formatting --- atst/routes/task_orders/new.py | 8 +------- js/components/upload_input.js | 2 +- js/lib/upload.js | 1 - 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index 2ea48a41..b9912f9b 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -1,10 +1,4 @@ -from flask import ( - g, - redirect, - render_template, - request as http_request, - url_for, -) +from flask import g, redirect, render_template, request as http_request, url_for from . import task_orders_bp from atst.domain.authz.decorator import user_can_access_decorator as user_can diff --git a/js/components/upload_input.js b/js/components/upload_input.js index 5254ca19..f15cfdbf 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -104,7 +104,7 @@ export default { this.sizeError = false }, getUploader: async function() { - return fetch('/upload-token', { credentials: "include" }) + return fetch('/upload-token', { credentials: 'include' }) .then(response => response.json()) .then(({ token, objectName }) => buildUploader(token, objectName)) }, diff --git a/js/lib/upload.js b/js/lib/upload.js index a9d06b07..8af4bb5a 100644 --- a/js/lib/upload.js +++ b/js/lib/upload.js @@ -72,7 +72,6 @@ class MockUploader { constructor(token, objectName) { this.token = token this.objectName = objectName - console.log("built MockUploader") } async upload(file, objectName) { From c324cde3b33bcbb3dc726fb28e96405be3f9b05b Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 26 Aug 2019 10:20:29 -0400 Subject: [PATCH 05/13] Update secrets baseline --- .secrets.baseline | 50 +++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 7d5b6411..7be51fef 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,8 +3,14 @@ "files": null, "lines": null }, - "generated_at": "2019-08-21T18:40:15Z", + "generated_at": "2019-08-27T20:13:28Z", "plugins_used": [ + { + "name": "AWSKeyDetector" + }, + { + "name": "ArtifactoryDetector" + }, { "base64_limit": 4.5, "name": "Base64HighEntropyString" @@ -21,13 +27,18 @@ }, { "name": "PrivateKeyDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "StripeDetector" } ], "results": { "Pipfile.lock": [ { "hashed_secret": "a355e3e3983231194cfc5981d48ea7ff9a7f9cb6", - "is_secret": false, "is_verified": false, "line_number": 4, "type": "Hex High Entropy String" @@ -36,16 +47,14 @@ "README.md": [ { "hashed_secret": "d141ce86b0584abb29ee7c24af9afb1e3d871f04", - "is_secret": false, "is_verified": false, - "line_number": 145, + "line_number": 156, "type": "Secret Keyword" } ], "alembic.ini": [ { "hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684", - "is_secret": false, "is_verified": false, "line_number": 38, "type": "Basic Auth Credentials" @@ -54,16 +63,28 @@ "alembic/versions/e0c6eb21771f_reset_migrations_with_new_schema.py": [ { "hashed_secret": "999a22300a564f9d2bdca555c2170465fd760ae3", - "is_secret": false, "is_verified": false, "line_number": 13, "type": "Hex High Entropy String" } ], + "alembic/versions/fda6bd7e1b65_clin_delete_cascade.py": [ + { + "hashed_secret": "61d8937fb12b982e07b933c083d9014c34159723", + "is_verified": false, + "line_number": 13, + "type": "Hex High Entropy String" + }, + { + "hashed_secret": "999a22300a564f9d2bdca555c2170465fd760ae3", + "is_verified": false, + "line_number": 14, + "type": "Hex High Entropy String" + } + ], "atst.ini.example": [ { "hashed_secret": "abcdb568713c255c81376829da20004ba9463fd3", - "is_secret": false, "is_verified": false, "line_number": 2, "type": "Secret Keyword" @@ -72,21 +93,18 @@ "config/base.ini": [ { "hashed_secret": "aa419433d95be86df254d499243bee1d5173f1ae", - "is_secret": false, "is_verified": false, "line_number": 5, "type": "Secret Keyword" }, { "hashed_secret": "afc848c316af1a89d49826c5ae9d00ed769415f3", - "is_secret": false, "is_verified": false, "line_number": 18, "type": "Secret Keyword" }, { "hashed_secret": "abcdb568713c255c81376829da20004ba9463fd3", - "is_secret": false, "is_verified": false, "line_number": 24, "type": "Secret Keyword" @@ -95,7 +113,6 @@ "ssl/certificate-authority/ca.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", - "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -104,7 +121,6 @@ "ssl/client-certs/atat.mil.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", - "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -113,7 +129,6 @@ "ssl/client-certs/bad-atat.mil.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", - "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -122,7 +137,6 @@ "ssl/client-certs/client-ca.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", - "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -131,7 +145,6 @@ "ssl/server-certs/dev.cac.atat.codes.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", - "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -140,7 +153,6 @@ "tests/acceptance/conftest.py": [ { "hashed_secret": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f", - "is_secret": false, "is_verified": false, "line_number": 48, "type": "Basic Auth Credentials" @@ -149,7 +161,6 @@ "tests/fixtures/chain/make-chain.sh": [ { "hashed_secret": "bad2e396920ce37fe53fc291f90b130d915375fb", - "is_secret": false, "is_verified": false, "line_number": 35, "type": "Secret Keyword" @@ -158,7 +169,6 @@ "tests/forms/test_validators.py": [ { "hashed_secret": "260408f687da9094705a841acda9b029563053ee", - "is_secret": false, "is_verified": false, "line_number": 30, "type": "Hex High Entropy String" @@ -167,7 +177,6 @@ "tests/routes/task_orders/test_new.py": [ { "hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207", - "is_secret": false, "is_verified": false, "line_number": 32, "type": "Hex High Entropy String" @@ -176,9 +185,8 @@ "tests/test_access.py": [ { "hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207", - "is_secret": false, "is_verified": false, - "line_number": 481, + "line_number": 523, "type": "Hex High Entropy String" } ] From 0e593a77f1b66da6141e6a58573ae4dfeed0bdfd Mon Sep 17 00:00:00 2001 From: richard-dds Date: Mon, 26 Aug 2019 10:26:26 -0400 Subject: [PATCH 06/13] Add permission check to upload_token route --- atst/routes/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index eba02c3e..fe916c5b 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -21,6 +21,8 @@ from atst.domain.users import Users from atst.domain.authnid import AuthenticationContext from atst.domain.auth import logout as _logout from atst.utils.flash import formatted_flash as flash +from atst.models.permissions import Permissions +from atst.domain.authz.decorator import user_can_access_decorator as user_can bp = Blueprint("atst", __name__) @@ -43,6 +45,7 @@ def root(): @bp.route("/upload-token") +@user_can(Permissions.CREATE_TASK_ORDER, message="edit task order form") def upload_token(): (token, object_name) = app.csp.files.get_token() render_args = {"token": token, "objectName": object_name} From 0566b525f6eb00d27db59bb037c002d3da9d8527 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Tue, 27 Aug 2019 16:26:52 -0400 Subject: [PATCH 07/13] Fix secrets file --- .secrets.baseline | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/.secrets.baseline b/.secrets.baseline index 7be51fef..814fd704 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -1,16 +1,10 @@ { "exclude": { - "files": null, + "files": "^.secrets.baseline$", "lines": null }, - "generated_at": "2019-08-27T20:13:28Z", + "generated_at": "2019-08-28T19:50:39Z", "plugins_used": [ - { - "name": "AWSKeyDetector" - }, - { - "name": "ArtifactoryDetector" - }, { "base64_limit": 4.5, "name": "Base64HighEntropyString" @@ -27,18 +21,13 @@ }, { "name": "PrivateKeyDetector" - }, - { - "name": "SlackDetector" - }, - { - "name": "StripeDetector" } ], "results": { "Pipfile.lock": [ { "hashed_secret": "a355e3e3983231194cfc5981d48ea7ff9a7f9cb6", + "is_secret": false, "is_verified": false, "line_number": 4, "type": "Hex High Entropy String" @@ -47,6 +36,7 @@ "README.md": [ { "hashed_secret": "d141ce86b0584abb29ee7c24af9afb1e3d871f04", + "is_secret": false, "is_verified": false, "line_number": 156, "type": "Secret Keyword" @@ -55,6 +45,7 @@ "alembic.ini": [ { "hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684", + "is_secret": false, "is_verified": false, "line_number": 38, "type": "Basic Auth Credentials" @@ -63,6 +54,7 @@ "alembic/versions/e0c6eb21771f_reset_migrations_with_new_schema.py": [ { "hashed_secret": "999a22300a564f9d2bdca555c2170465fd760ae3", + "is_secret": false, "is_verified": false, "line_number": 13, "type": "Hex High Entropy String" @@ -71,12 +63,14 @@ "alembic/versions/fda6bd7e1b65_clin_delete_cascade.py": [ { "hashed_secret": "61d8937fb12b982e07b933c083d9014c34159723", + "is_secret": false, "is_verified": false, "line_number": 13, "type": "Hex High Entropy String" }, { "hashed_secret": "999a22300a564f9d2bdca555c2170465fd760ae3", + "is_secret": false, "is_verified": false, "line_number": 14, "type": "Hex High Entropy String" @@ -85,6 +79,7 @@ "atst.ini.example": [ { "hashed_secret": "abcdb568713c255c81376829da20004ba9463fd3", + "is_secret": false, "is_verified": false, "line_number": 2, "type": "Secret Keyword" @@ -93,18 +88,21 @@ "config/base.ini": [ { "hashed_secret": "aa419433d95be86df254d499243bee1d5173f1ae", + "is_secret": false, "is_verified": false, "line_number": 5, "type": "Secret Keyword" }, { "hashed_secret": "afc848c316af1a89d49826c5ae9d00ed769415f3", + "is_secret": false, "is_verified": false, "line_number": 18, "type": "Secret Keyword" }, { "hashed_secret": "abcdb568713c255c81376829da20004ba9463fd3", + "is_secret": false, "is_verified": false, "line_number": 24, "type": "Secret Keyword" @@ -113,6 +111,7 @@ "ssl/certificate-authority/ca.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -121,6 +120,7 @@ "ssl/client-certs/atat.mil.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -129,6 +129,7 @@ "ssl/client-certs/bad-atat.mil.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -137,6 +138,7 @@ "ssl/client-certs/client-ca.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -145,6 +147,7 @@ "ssl/server-certs/dev.cac.atat.codes.key": [ { "hashed_secret": "be4fc4886bd949b369d5e092eb87494f12e57e5b", + "is_secret": false, "is_verified": false, "line_number": 1, "type": "Private Key" @@ -153,6 +156,7 @@ "tests/acceptance/conftest.py": [ { "hashed_secret": "bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f", + "is_secret": false, "is_verified": false, "line_number": 48, "type": "Basic Auth Credentials" @@ -161,6 +165,7 @@ "tests/fixtures/chain/make-chain.sh": [ { "hashed_secret": "bad2e396920ce37fe53fc291f90b130d915375fb", + "is_secret": false, "is_verified": false, "line_number": 35, "type": "Secret Keyword" @@ -169,6 +174,7 @@ "tests/forms/test_validators.py": [ { "hashed_secret": "260408f687da9094705a841acda9b029563053ee", + "is_secret": false, "is_verified": false, "line_number": 30, "type": "Hex High Entropy String" @@ -177,6 +183,7 @@ "tests/routes/task_orders/test_new.py": [ { "hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207", + "is_secret": false, "is_verified": false, "line_number": 32, "type": "Hex High Entropy String" @@ -185,6 +192,7 @@ "tests/test_access.py": [ { "hashed_secret": "e4f14805dfd1e6af030359090c535e149e6b4207", + "is_secret": false, "is_verified": false, "line_number": 523, "type": "Hex High Entropy String" @@ -193,3 +201,4 @@ }, "version": "0.12.5" } + From 67a4bb602d164579fa66bf881536a08efb5f90ac Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 28 Aug 2019 11:59:11 -0400 Subject: [PATCH 08/13] Require portfolio id in upload-token It's necessary for the authz decorator --- atst/routes/__init__.py | 10 ---------- atst/routes/task_orders/new.py | 20 +++++++++++++++++++- js/components/upload_input.js | 7 ++++++- templates/components/upload_input.html | 3 ++- templates/task_orders/step_1.html | 3 +-- 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index fe916c5b..a99c384c 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -9,7 +9,6 @@ from flask import ( request, make_response, current_app as app, - jsonify, ) from jinja2.exceptions import TemplateNotFound @@ -44,15 +43,6 @@ def root(): return render_template("login.html", redirect_url=redirect_url) -@bp.route("/upload-token") -@user_can(Permissions.CREATE_TASK_ORDER, message="edit task order form") -def upload_token(): - (token, object_name) = app.csp.files.get_token() - render_args = {"token": token, "objectName": object_name} - - return jsonify(render_args) - - @bp.route("/help") @bp.route("/help/") def helpdocs(doc=None): diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index b9912f9b..b6053dc0 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -1,4 +1,12 @@ -from flask import g, redirect, render_template, request as http_request, url_for +from flask import ( + g, + redirect, + render_template, + request as http_request, + url_for, + current_app as app, + jsonify, +) from . import task_orders_bp from atst.domain.authz.decorator import user_can_access_decorator as user_can @@ -64,6 +72,16 @@ def update_task_order( ) +@task_orders_bp.route("/task_orders//upload-token") +@user_can(Permissions.CREATE_TASK_ORDER, message="edit task order form") +def upload_token(portfolio_id): + print(app.csp) + (token, object_name) = app.csp.files.get_token() + render_args = {"token": token, "objectName": object_name} + + return jsonify(render_args) + + @task_orders_bp.route("/task_orders//edit") @user_can(Permissions.CREATE_TASK_ORDER, message="edit task order form") def edit(task_order_id): diff --git a/js/components/upload_input.js b/js/components/upload_input.js index f15cfdbf..83e173fd 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -34,6 +34,9 @@ export default { type: Boolean, default: true, }, + portfolioId: { + type: String, + }, }, data: function() { @@ -104,7 +107,9 @@ export default { this.sizeError = false }, getUploader: async function() { - return fetch('/upload-token', { credentials: 'include' }) + return fetch(`/task_orders/${this.portfolioId}/upload-token`, { + credentials: 'include', + }) .then(response => response.json()) .then(({ token, objectName }) => buildUploader(token, objectName)) }, diff --git a/templates/components/upload_input.html b/templates/components/upload_input.html index f78b6b31..04eb55aa 100644 --- a/templates/components/upload_input.html +++ b/templates/components/upload_input.html @@ -1,6 +1,6 @@ {% from "components/icon.html" import Icon %} -{% macro UploadInput(field, show_label=False, watch=False, token="", object_name="") -%} +{% macro UploadInput(field, portfolio_id, show_label=False, watch=False, token="", object_name="") -%} diff --git a/templates/task_orders/step_1.html b/templates/task_orders/step_1.html index 843b8c0b..dd17c1f1 100644 --- a/templates/task_orders/step_1.html +++ b/templates/task_orders/step_1.html @@ -14,8 +14,7 @@ {% set next_button_text = "Next: Add TO Number" %} {% set step = "1" %} - {% block to_builder_form_field %} {{ TOFormStepHeader('task_orders.form.supporting_docs_header' | translate, 'task_orders.form.supporting_docs_text' | translate) }} - {{ UploadInput(form.pdf, watch=True, token=token, object_name=object_name) }} + {{ UploadInput(form.pdf, portfolio.id, watch=True, token=token, object_name=object_name) }} {% endblock %} From 11c1c37d7fc8bb1a36df8a7ee3e7580a41c8feda Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 28 Aug 2019 14:39:28 -0400 Subject: [PATCH 09/13] Remove unnecessary macro and Vue props --- js/components/upload_input.js | 5 +---- templates/components/upload_input.html | 2 +- templates/task_orders/step_1.html | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/js/components/upload_input.js b/js/components/upload_input.js index 83e173fd..428cb367 100644 --- a/js/components/upload_input.js +++ b/js/components/upload_input.js @@ -1,6 +1,3 @@ -import createNumberMask from 'text-mask-addons/dist/createNumberMask' -import { conformToMask } from 'vue-text-mask' - import { emitEvent } from '../lib/emitters' import FormMixin from '../mixins/form' import textinput from './text_input' @@ -68,7 +65,7 @@ export default { } const uploader = await this.getUploader() - const response = await uploader.upload(file, this.objectName) + const response = await uploader.upload(file) if (response.ok) { this.attachment = e.target.value this.$refs.attachmentFilename.value = file.name diff --git a/templates/components/upload_input.html b/templates/components/upload_input.html index 04eb55aa..c2cc176d 100644 --- a/templates/components/upload_input.html +++ b/templates/components/upload_input.html @@ -1,6 +1,6 @@ {% from "components/icon.html" import Icon %} -{% macro UploadInput(field, portfolio_id, show_label=False, watch=False, token="", object_name="") -%} +{% macro UploadInput(field, portfolio_id, show_label=False, watch=False) -%} Date: Wed, 28 Aug 2019 14:52:28 -0400 Subject: [PATCH 10/13] Fix Vue tests --- atst/routes/task_orders/new.py | 1 - js/test_templates/upload_input_error_template.html | 7 ++++--- js/test_templates/upload_input_template.html | 7 ++++--- tests/render_vue_component.py | 8 ++------ 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/atst/routes/task_orders/new.py b/atst/routes/task_orders/new.py index b6053dc0..201a6923 100644 --- a/atst/routes/task_orders/new.py +++ b/atst/routes/task_orders/new.py @@ -75,7 +75,6 @@ def update_task_order( @task_orders_bp.route("/task_orders//upload-token") @user_can(Permissions.CREATE_TASK_ORDER, message="edit task order form") def upload_token(portfolio_id): - print(app.csp) (token, object_name) = app.csp.files.get_token() render_args = {"token": token, "objectName": object_name} diff --git a/js/test_templates/upload_input_error_template.html b/js/test_templates/upload_input_error_template.html index 02256f0d..e8e5aba8 100644 --- a/js/test_templates/upload_input_error_template.html +++ b/js/test_templates/upload_input_error_template.html @@ -4,10 +4,9 @@ v-bind:initial-errors='true' v-bind:watch='false' + v-bind:portfolio-id="''" name='pdf' :optional='false' - v-bind:token='token' - v-bind:object-name='"object_name"' >
@@ -36,11 +35,13 @@ v-bind:value="attachment" type="file"> -
+ Test Error Message diff --git a/js/test_templates/upload_input_template.html b/js/test_templates/upload_input_template.html index 70c73407..c5954616 100644 --- a/js/test_templates/upload_input_template.html +++ b/js/test_templates/upload_input_template.html @@ -4,10 +4,9 @@ v-bind:initial-data='initialvalue' v-bind:watch='false' + v-bind:portfolio-id="''" name='pdf' :optional='false' - v-bind:token='token' - v-bind:object-name='"object_name"' >
@@ -36,11 +35,13 @@ v-bind:value="attachment" type="file"> -
+
diff --git a/tests/render_vue_component.py b/tests/render_vue_component.py index b502ea93..ab33303c 100644 --- a/tests/render_vue_component.py +++ b/tests/render_vue_component.py @@ -74,15 +74,11 @@ def test_make_checkbox_input_template(checkbox_input_macro, initial_value_form): def test_make_upload_input_template(upload_input_macro, task_order_form): - rendered_upload_macro = upload_input_macro( - task_order_form.pdf, token="token", object_name="object_name" - ) + rendered_upload_macro = upload_input_macro(task_order_form.pdf) write_template(rendered_upload_macro, "upload_input_template.html") def test_make_upload_input_error_template(upload_input_macro, task_order_form): task_order_form.validate() - rendered_upload_macro = upload_input_macro( - task_order_form.pdf, token="token", object_name="object_name" - ) + rendered_upload_macro = upload_input_macro(task_order_form.pdf) write_template(rendered_upload_macro, "upload_input_error_template.html") From f54e673520b7487a2a7138e151952ed81a8de38c Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 28 Aug 2019 14:57:39 -0400 Subject: [PATCH 11/13] Remove unused imports --- atst/routes/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/atst/routes/__init__.py b/atst/routes/__init__.py index a99c384c..eaa447be 100644 --- a/atst/routes/__init__.py +++ b/atst/routes/__init__.py @@ -20,8 +20,6 @@ from atst.domain.users import Users from atst.domain.authnid import AuthenticationContext from atst.domain.auth import logout as _logout from atst.utils.flash import formatted_flash as flash -from atst.models.permissions import Permissions -from atst.domain.authz.decorator import user_can_access_decorator as user_can bp = Blueprint("atst", __name__) From d775bce3b74e6e6b4f0cc5b457123313cbc486d1 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 28 Aug 2019 15:14:12 -0400 Subject: [PATCH 12/13] Fix incorrect `this` in azure upload --- js/lib/upload.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/lib/upload.js b/js/lib/upload.js index 8af4bb5a..f2c5440b 100644 --- a/js/lib/upload.js +++ b/js/lib/upload.js @@ -31,7 +31,7 @@ class AzureUploader { `${this.objectName}`, f.target.result, options, - function(err, result) { + (err, result) => { if (err) { resolve({ ok: false }) } else { From e03e98095bc22474c68055b415aaf96c4cf07444 Mon Sep 17 00:00:00 2001 From: richard-dds Date: Wed, 28 Aug 2019 15:19:46 -0400 Subject: [PATCH 13/13] Re-render Vue test templates --- js/test_templates/upload_input_error_template.html | 1 + js/test_templates/upload_input_template.html | 1 + 2 files changed, 2 insertions(+) diff --git a/js/test_templates/upload_input_error_template.html b/js/test_templates/upload_input_error_template.html index e8e5aba8..50c1c3ab 100644 --- a/js/test_templates/upload_input_error_template.html +++ b/js/test_templates/upload_input_error_template.html @@ -35,6 +35,7 @@ v-bind:value="attachment" type="file"> +