Additional validation and escaping for file names.
This adds additional front and backend validations for task order file names. We are now restricting file names to a whitelist regex of [A-Za-z0-9\-_ \.] for simplicity. Note: On the frontend, the filename string must have at least one character. This is not true in the backend validation; because of the way the entire task order form is validated, requiring input would break the business logic currently implemented.
This commit is contained in:
parent
05bc8c3819
commit
5213657b0f
@ -7,7 +7,7 @@ from wtforms.fields import (
|
|||||||
HiddenField,
|
HiddenField,
|
||||||
)
|
)
|
||||||
from wtforms.fields.html5 import DateField
|
from wtforms.fields.html5 import DateField
|
||||||
from wtforms.validators import Required, Length, NumberRange, ValidationError
|
from wtforms.validators import Required, Length, NumberRange, ValidationError, Regexp
|
||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from numbers import Number
|
from numbers import Number
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ from .data import JEDI_CLIN_TYPES
|
|||||||
from .fields import SelectField
|
from .fields import SelectField
|
||||||
from .forms import BaseForm, remove_empty_string
|
from .forms import BaseForm, remove_empty_string
|
||||||
from atst.utils.localization import translate
|
from atst.utils.localization import translate
|
||||||
|
from .validators import REGEX_ALPHA_NUMERIC
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
|
|
||||||
MAX_CLIN_AMOUNT = 1000000000
|
MAX_CLIN_AMOUNT = 1000000000
|
||||||
@ -116,7 +117,10 @@ class AttachmentForm(BaseForm):
|
|||||||
filename = HiddenField(
|
filename = HiddenField(
|
||||||
id="attachment_filename",
|
id="attachment_filename",
|
||||||
validators=[
|
validators=[
|
||||||
Length(max=100, message=translate("forms.attachment.filename.length_error"))
|
Length(
|
||||||
|
max=100, message=translate("forms.attachment.filename.length_error")
|
||||||
|
),
|
||||||
|
Regexp(regex=REGEX_ALPHA_NUMERIC),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
object_name = HiddenField(
|
object_name = HiddenField(
|
||||||
@ -124,7 +128,8 @@ class AttachmentForm(BaseForm):
|
|||||||
validators=[
|
validators=[
|
||||||
Length(
|
Length(
|
||||||
max=40, message=translate("forms.attachment.object_name.length_error")
|
max=40, message=translate("forms.attachment.object_name.length_error")
|
||||||
)
|
),
|
||||||
|
Regexp(regex=REGEX_ALPHA_NUMERIC),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
accept = ".pdf,application/pdf"
|
accept = ".pdf,application/pdf"
|
||||||
|
@ -8,6 +8,9 @@ import pendulum
|
|||||||
from atst.utils.localization import translate
|
from atst.utils.localization import translate
|
||||||
|
|
||||||
|
|
||||||
|
REGEX_ALPHA_NUMERIC = "^[A-Za-z0-9\-_ \.]*$"
|
||||||
|
|
||||||
|
|
||||||
def DateRange(lower_bound=None, upper_bound=None, message=None):
|
def DateRange(lower_bound=None, upper_bound=None, message=None):
|
||||||
def _date_range(form, field):
|
def _date_range(form, field):
|
||||||
if field.data is None:
|
if field.data is None:
|
||||||
|
@ -70,7 +70,7 @@ describe('UploadInput Test', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const component = wrapper.find(uploadinput)
|
const component = wrapper.find(uploadinput)
|
||||||
const event = { target: { value: '', files: [{ name: '' }] } }
|
const event = { target: { value: '', files: [{ name: 'sample.pdf' }] } }
|
||||||
|
|
||||||
component.setMethods({
|
component.setMethods({
|
||||||
getUploader: async () => new MockUploader('token', 'objectName'),
|
getUploader: async () => new MockUploader('token', 'objectName'),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { buildUploader } from '../lib/upload'
|
import { buildUploader } from '../lib/upload'
|
||||||
import { emitFieldChange } from '../lib/emitters'
|
import { emitFieldChange } from '../lib/emitters'
|
||||||
|
import inputValidations from '../lib/input_validations'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'uploadinput',
|
name: 'uploadinput',
|
||||||
@ -28,6 +29,7 @@ export default {
|
|||||||
changed: false,
|
changed: false,
|
||||||
uploadError: false,
|
uploadError: false,
|
||||||
sizeError: false,
|
sizeError: false,
|
||||||
|
filenameError: false,
|
||||||
downloadLink: '',
|
downloadLink: '',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -50,6 +52,10 @@ export default {
|
|||||||
this.sizeError = true
|
this.sizeError = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (!this.validateFileName(file.name)) {
|
||||||
|
this.filenameError = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const uploader = await this.getUploader()
|
const uploader = await this.getUploader()
|
||||||
const response = await uploader.upload(file)
|
const response = await uploader.upload(file)
|
||||||
@ -71,6 +77,10 @@ export default {
|
|||||||
this.uploadError = true
|
this.uploadError = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
validateFileName: function(name) {
|
||||||
|
const regex = inputValidations.restrictedFileName.match
|
||||||
|
return regex.test(name)
|
||||||
|
},
|
||||||
removeAttachment: function(e) {
|
removeAttachment: function(e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
this.attachment = null
|
this.attachment = null
|
||||||
@ -118,7 +128,8 @@ export default {
|
|||||||
return (
|
return (
|
||||||
(!this.changed && this.initialErrors) ||
|
(!this.changed && this.initialErrors) ||
|
||||||
this.uploadError ||
|
this.uploadError ||
|
||||||
this.sizeError
|
this.sizeError ||
|
||||||
|
this.filenameError
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
valid: function() {
|
valid: function() {
|
||||||
|
@ -104,4 +104,11 @@ export default {
|
|||||||
unmask: ['(', ')', '-', ' '],
|
unmask: ['(', ')', '-', ' '],
|
||||||
validationError: 'Please enter a 10-digit phone number',
|
validationError: 'Please enter a 10-digit phone number',
|
||||||
},
|
},
|
||||||
|
restrictedFileName: {
|
||||||
|
mask: false,
|
||||||
|
match: /^[A-Za-z0-9\-_ \.]+$/,
|
||||||
|
unmask: [],
|
||||||
|
validationError:
|
||||||
|
'File names can only contain the characters A-Z, 0-9, space, hyphen, underscore, and period.',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,9 @@
|
|||||||
<template v-if="sizeError">
|
<template v-if="sizeError">
|
||||||
<span class="usa-input__message">{{ "forms.task_order.size_error" | translate }}</span>
|
<span class="usa-input__message">{{ "forms.task_order.size_error" | translate }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="filenameError">
|
||||||
|
<span class="usa-input__message">{{ "forms.task_order.filename_error" | translate }}</span>
|
||||||
|
</template>
|
||||||
{% for error, error_messages in field.errors.items() %}
|
{% for error, error_messages in field.errors.items() %}
|
||||||
<span class="usa-input__message">{{error_messages[0]}}</span>
|
<span class="usa-input__message">{{error_messages[0]}}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -292,6 +292,7 @@ forms:
|
|||||||
task_order:
|
task_order:
|
||||||
upload_error: There was an error uploading your file. Please try again. If you encounter repeated problems uploading this file, please contact CCPO.
|
upload_error: There was an error uploading your file. Please try again. If you encounter repeated problems uploading this file, please contact CCPO.
|
||||||
size_error: The file you have selected is too large. Please choose a file no larger than 64MB.
|
size_error: The file you have selected is too large. Please choose a file no larger than 64MB.
|
||||||
|
filename_error: File names can only contain the characters A-Z, 0-9, space, hyphen, underscore, and period.
|
||||||
defense_component_label: Select DoD component(s) funding your Portfolio
|
defense_component_label: Select DoD component(s) funding your Portfolio
|
||||||
file_format_not_allowed: Only PDF or PNG files can be uploaded.
|
file_format_not_allowed: Only PDF or PNG files can be uploaded.
|
||||||
number_description: Task order number (13 digits)
|
number_description: Task order number (13 digits)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user