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,
|
||||
)
|
||||
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 numbers import Number
|
||||
|
||||
@ -15,6 +15,7 @@ from .data import JEDI_CLIN_TYPES
|
||||
from .fields import SelectField
|
||||
from .forms import BaseForm, remove_empty_string
|
||||
from atst.utils.localization import translate
|
||||
from .validators import REGEX_ALPHA_NUMERIC
|
||||
from flask import current_app as app
|
||||
|
||||
MAX_CLIN_AMOUNT = 1000000000
|
||||
@ -116,7 +117,10 @@ class AttachmentForm(BaseForm):
|
||||
filename = HiddenField(
|
||||
id="attachment_filename",
|
||||
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(
|
||||
@ -124,7 +128,8 @@ class AttachmentForm(BaseForm):
|
||||
validators=[
|
||||
Length(
|
||||
max=40, message=translate("forms.attachment.object_name.length_error")
|
||||
)
|
||||
),
|
||||
Regexp(regex=REGEX_ALPHA_NUMERIC),
|
||||
],
|
||||
)
|
||||
accept = ".pdf,application/pdf"
|
||||
|
@ -8,6 +8,9 @@ import pendulum
|
||||
from atst.utils.localization import translate
|
||||
|
||||
|
||||
REGEX_ALPHA_NUMERIC = "^[A-Za-z0-9\-_ \.]*$"
|
||||
|
||||
|
||||
def DateRange(lower_bound=None, upper_bound=None, message=None):
|
||||
def _date_range(form, field):
|
||||
if field.data is None:
|
||||
|
@ -70,7 +70,7 @@ describe('UploadInput Test', () => {
|
||||
})
|
||||
|
||||
const component = wrapper.find(uploadinput)
|
||||
const event = { target: { value: '', files: [{ name: '' }] } }
|
||||
const event = { target: { value: '', files: [{ name: 'sample.pdf' }] } }
|
||||
|
||||
component.setMethods({
|
||||
getUploader: async () => new MockUploader('token', 'objectName'),
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { buildUploader } from '../lib/upload'
|
||||
import { emitFieldChange } from '../lib/emitters'
|
||||
import inputValidations from '../lib/input_validations'
|
||||
|
||||
export default {
|
||||
name: 'uploadinput',
|
||||
@ -28,6 +29,7 @@ export default {
|
||||
changed: false,
|
||||
uploadError: false,
|
||||
sizeError: false,
|
||||
filenameError: false,
|
||||
downloadLink: '',
|
||||
}
|
||||
},
|
||||
@ -50,6 +52,10 @@ export default {
|
||||
this.sizeError = true
|
||||
return
|
||||
}
|
||||
if (!this.validateFileName(file.name)) {
|
||||
this.filenameError = true
|
||||
return
|
||||
}
|
||||
|
||||
const uploader = await this.getUploader()
|
||||
const response = await uploader.upload(file)
|
||||
@ -71,6 +77,10 @@ export default {
|
||||
this.uploadError = true
|
||||
}
|
||||
},
|
||||
validateFileName: function(name) {
|
||||
const regex = inputValidations.restrictedFileName.match
|
||||
return regex.test(name)
|
||||
},
|
||||
removeAttachment: function(e) {
|
||||
e.preventDefault()
|
||||
this.attachment = null
|
||||
@ -118,7 +128,8 @@ export default {
|
||||
return (
|
||||
(!this.changed && this.initialErrors) ||
|
||||
this.uploadError ||
|
||||
this.sizeError
|
||||
this.sizeError ||
|
||||
this.filenameError
|
||||
)
|
||||
},
|
||||
valid: function() {
|
||||
|
@ -104,4 +104,11 @@ export default {
|
||||
unmask: ['(', ')', '-', ' '],
|
||||
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">
|
||||
<span class="usa-input__message">{{ "forms.task_order.size_error" | translate }}</span>
|
||||
</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() %}
|
||||
<span class="usa-input__message">{{error_messages[0]}}</span>
|
||||
{% endfor %}
|
||||
|
@ -292,6 +292,7 @@ forms:
|
||||
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.
|
||||
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
|
||||
file_format_not_allowed: Only PDF or PNG files can be uploaded.
|
||||
number_description: Task order number (13 digits)
|
||||
|
Loading…
x
Reference in New Issue
Block a user