Skip to content

Commit

Permalink
Adding form validation to prevent names > 255 char. (#3026)
Browse files Browse the repository at this point in the history
* Introduce name field validation in front & backend.
  • Loading branch information
jkppr authored Jan 26, 2024
1 parent 2cf70f2 commit 57c585c
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 24 deletions.
4 changes: 2 additions & 2 deletions end_to_end_tests/upload_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_large_upload_csv(self):
is correct."""

# create a new sketch
rand = random.randint(0, 10000)
rand = str(random.randint(0, 10000))
sketch = self.api.create_sketch(name=rand)
self.sketch = sketch

Expand Down Expand Up @@ -185,7 +185,7 @@ def test_large_upload_csv_over_flush_limit(self):
is correct."""

# create a new sketch
rand = random.randint(0, 10000)
rand = str(random.randint(0, 10000))
sketch = self.api.create_sketch(name=rand)
self.sketch = sketch

Expand Down
5 changes: 4 additions & 1 deletion timesketch/api/v1/resources/sketch.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,10 @@ def post(self):
"""
form = forms.NameDescriptionForm.build(request)
if not form.validate_on_submit():
abort(HTTP_STATUS_CODE_BAD_REQUEST, "Unable to validate form data.")
error_message = "Unable to validate form data: "
for error in form.errors.values():
error_message += f"{error}, "
abort(HTTP_STATUS_CODE_BAD_REQUEST, error_message[:-2])

sketch = Sketch(name=form.name.data, description=form.description.data)
db_session.add(sketch)
Expand Down
12 changes: 11 additions & 1 deletion timesketch/api/v1/resources/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,17 @@ def _upload_file(
"""
_filename, _extension = os.path.splitext(file_storage.filename)
file_extension = _extension.lstrip(".")
timeline_name = form.get("name", _filename.rstrip("."))
timeline_name = str(form.get("name", _filename.rstrip(".")))
if len(timeline_name) == 0 or timeline_name == "null":
abort(
HTTP_STATUS_CODE_BAD_REQUEST,
"Timeline name cannot be empty.",
)
if len(timeline_name) > 255:
abort(
HTTP_STATUS_CODE_BAD_REQUEST,
"Timeline name needs to be less than 255 characters.",
)

# We do not need a human readable filename or
# datastore index name, so we use UUIDs here.
Expand Down
8 changes: 4 additions & 4 deletions timesketch/api/v1/resources/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,10 @@ def post(self, sketch_id):
"""
form = forms.SaveViewForm.build(request)
if not form.validate_on_submit():
abort(
HTTP_STATUS_CODE_BAD_REQUEST,
"Unable to save view, not able to validate form data.",
)
error_message = "Unable to save view, not able to validate form data: "
for error in form.errors.values():
error_message += f"{error}, "
abort(HTTP_STATUS_CODE_BAD_REQUEST, error_message[:-2])

sketch = Sketch.get_with_acl(sketch_id)
if not sketch:
Expand Down
18 changes: 12 additions & 6 deletions timesketch/frontend-ng/src/components/Explore/EventList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,28 @@ limitations under the License.
<h3>Save Search</h3>
<br />
<v-text-field
clearable
v-model="saveSearchFormName"
required
placeholder="Name your saved search"
outlined
dense
autofocus
@focus="$event.target.select()"
:rules="saveSearchNameRules"
>
</v-text-field>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text @click="saveSearchMenu = false"> Cancel </v-btn>
<v-btn text color="primary" @click="saveSearch" :disabled="!saveSearchFormName"> Save </v-btn>
<v-btn
text
color="primary"
@click="saveSearch"
:disabled="!saveSearchFormName || saveSearchFormName.length > 255"
>
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
Expand Down Expand Up @@ -388,10 +397,7 @@ limitations under the License.
<div class="d-inline-block">
<v-btn icon small @click="toggleDetailedEvent(item)" v-if="item._source.comment.length">
<v-badge :offset-y="10" :offset-x="10" bordered :content="item._source.comment.length">
<v-icon
:title="item['showDetails'] ? 'Close event &amp; comments' : 'Open event &amp; comments'"
small
>
<v-icon :title="item['showDetails'] ? 'Close event &amp; comments' : 'Open event &amp; comments'" small>
mdi-comment-text-multiple-outline
</v-icon>
</v-badge>
Expand All @@ -409,7 +415,6 @@ limitations under the License.
<v-icon title="Close comments"> mdi-comment-remove-outline </v-icon>
</v-btn>
</div>

</template>
</v-data-table>
</div>
Expand Down Expand Up @@ -507,6 +512,7 @@ export default {
columnDialog: false,
saveSearchMenu: false,
saveSearchFormName: '',
saveSearchNameRules: [(v) => !!v || 'Name is required.', (v) => (v && v.length <= 255) || 'Name is too long.'],
selectedEventTags: [],
tagConfig: {
good: { color: 'green', textColor: 'white', label: 'mdi-check-circle-outline' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,12 @@ limitations under the License.
<v-form @submit.prevent="rename()">
<h3>Rename timeline</h3>
<br />
<v-text-field outlined dense autofocus v-model="newTimelineName" @focus="$event.target.select()">
<v-text-field clearable outlined dense autofocus v-model="newTimelineName" @focus="$event.target.select()" :rules="timelineNameRules">
</v-text-field>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text @click="dialogRename = false"> Cancel </v-btn>
<v-btn color="primary" text @click="rename()"> Save </v-btn>
<v-btn :disabled="!newTimelineName || newTimelineName.length > 255" color="primary" text @click="rename()"> Save </v-btn>
</v-card-actions>
</v-form>
</v-card>
Expand Down Expand Up @@ -357,6 +357,10 @@ export default {
['#DEBBFF', '#9AB0FB', '#CFFBE2'],
],
deleteConfirmation: false,
timelineNameRules: [
(v) => !!v || 'Timeline name is required.',
(v) => (v && v.length <= 255) || 'Timeline name is too long.',
],
}
},
computed: {
Expand Down
19 changes: 17 additions & 2 deletions timesketch/frontend-ng/src/components/RenameSketch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,22 @@ limitations under the License.
<h3>Rename sketch</h3>
<br />
<v-form @submit.prevent="renameSketch()">
<v-text-field outlined dense autofocus v-model="newSketchName" @focus="$event.target.select()"> </v-text-field>
<v-text-field
outlined
dense
autofocus
v-model="newSketchName"
@focus="$event.target.select()"
clearable
:rules="sketchNameRules"
>
</v-text-field>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text @click="closeDialog()"> Cancel </v-btn>
<v-btn text color="primary" @click="renameSketch()"> Save </v-btn>
<v-btn :disabled="!newSketchName || newSketchName.length > 255" text color="primary" @click="renameSketch()">
Save
</v-btn>
</v-card-actions>
</v-form>
</div>
Expand All @@ -35,6 +46,10 @@ export default {
data() {
return {
newSketchName: '',
sketchNameRules: [
(v) => !!v || 'Sketch name is required.',
(v) => (v && v.length <= 255) || 'Sketch name is too long.',
],
}
},
computed: {
Expand Down
22 changes: 20 additions & 2 deletions timesketch/frontend-ng/src/components/UploadForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,13 @@ limitations under the License.
</div>

<div v-if="fileName">
<v-text-field label="Timeline Name" outlined v-model="form.name"></v-text-field>
<v-text-field
label="Timeline Name"
outlined
v-model="form.name"
clearable
:rules="timelineNameRules"
></v-text-field>
<v-radio-group v-if="extension === 'csv'" v-model="CSVDelimiter">
<template v-slot:label>
<div>Choose <strong>CSV delimiter</strong></div>
Expand Down Expand Up @@ -141,7 +147,15 @@ limitations under the License.
<v-spacer></v-spacer>
<v-btn text @click="dialog = false"> Cancel </v-btn>
<v-btn v-if="fileName" text @click="clearFormData()"> Select another file </v-btn>
<v-btn color="primary" text @click="submitForm()" v-if="!(error.length > 0 || !fileName)"> Submit </v-btn>
<v-btn
color="primary"
text
@click="submitForm()"
v-if="!(error.length > 0 || !fileName)"
:disabled="!form.name || form.name.length > 255"
>
Submit
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
Expand Down Expand Up @@ -173,6 +187,10 @@ export default {
file: '',
},
fileName: '',
timelineNameRules: [
(v) => !!v || 'Timeline name is required.',
(v) => (v && v.length <= 255) || 'Timeline name is too long.',
],
fileMetaData: {},
error: [],
percentCompleted: 0,
Expand Down
23 changes: 21 additions & 2 deletions timesketch/frontend-ng/src/views/Home.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,27 @@ limitations under the License.
<h3>New sketch</h3>
<br />
<v-form @submit.prevent="createSketch()">
<v-text-field v-model="sketchForm.name" outlined dense placeholder="Name your sketch" autofocus>
<v-text-field
v-model="sketchForm.name"
outlined
dense
placeholder="Name your sketch"
autofocus
clearable
:rules="sketchNameRules"
>
</v-text-field>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text @click="createSketchDialog = false"> Cancel </v-btn>
<v-btn :disabled="!sketchForm.name" @click="createSketch()" color="primary" text> Create </v-btn>
<v-btn
:disabled="!sketchForm.name || sketchForm.name.length > 255"
@click="createSketch()"
color="primary"
text
>
Create
</v-btn>
</v-card-actions>
</v-form>
</v-card>
Expand Down Expand Up @@ -114,6 +129,10 @@ export default {
},
createSketchDialog: false,
scenarioTemplates: [],
sketchNameRules: [
(v) => !!v || 'Sketch name is required.',
(v) => (v && v.length <= 255) || 'Sketch name is too long.',
],
}
},
computed: {
Expand Down
22 changes: 20 additions & 2 deletions timesketch/lib/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,16 @@ class UsernamePasswordForm(BaseForm):
class NameDescriptionForm(BaseForm):
"""Generic form for name and description forms. Used in multiple places."""

name = StringField("Name", validators=[DataRequired()])
name = StringField(
"Name",
validators=[
DataRequired(),
Length(
max=255,
message="Name must be less than 255 characters.",
),
],
)
description = StringField("Description", widget=widgets.TextArea())


Expand Down Expand Up @@ -161,7 +170,16 @@ class TogglePublic(BaseForm):
class SaveViewForm(BaseForm):
"""Form used to save a view."""

name = StringField("Name")
name = StringField(
"Name",
validators=[
DataRequired(),
Length(
max=255,
message="Name must be less than 255 characters.",
),
],
)
description = StringField("Description", validators=[Optional()])
query = StringField("Query")
filter = StringField("Filter")
Expand Down

0 comments on commit 57c585c

Please sign in to comment.