From e154faaf32dae51b16f9aa398f2b67cac5adf296 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 21 May 2021 05:12:53 -0400 Subject: [PATCH] add idempotency tokens to upload endpoints --- debug/curl/upload_tts.py | 2 ++ debug/curl/upload_w2l.py | 4 +++- .../2021-05-15-071545_asset_upload_jobs/up.sql | 10 +++++++++- src/endpoints/tts/enqueue_upload_tts_model.rs | 16 ++++++++++++++++ src/endpoints/w2l/enqueue_upload_w2l_template.rs | 16 ++++++++++++++++ 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/debug/curl/upload_tts.py b/debug/curl/upload_tts.py index 5a696c86bf..f8da0109fd 100755 --- a/debug/curl/upload_tts.py +++ b/debug/curl/upload_tts.py @@ -2,6 +2,7 @@ import requests import re +import uuid login_url = 'http://localhost:12345/login' upload_url = 'http://localhost:12345/tts/upload' @@ -32,6 +33,7 @@ print("===== Upload TTS=====") cookies = { 'session': session_cookie } payload = { + 'idempotency_token': str(uuid.uuid4()), 'title': 'this is a new text to speech model', 'download_url': 'https://website.com', } diff --git a/debug/curl/upload_w2l.py b/debug/curl/upload_w2l.py index 9479de1327..37b6e02d55 100755 --- a/debug/curl/upload_w2l.py +++ b/debug/curl/upload_w2l.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 -import requests import re +import requests +import uuid login_url = 'http://localhost:12345/login' upload_url = 'http://localhost:12345/w2l/upload' @@ -32,6 +33,7 @@ print("===== Upload W2L =====") cookies = { 'session': session_cookie } payload = { + 'idempotency_token': str(uuid.uuid4()), 'title': 'this is a new text to W2L template', 'download_url': 'https://video.com', } diff --git a/migrations/2021-05-15-071545_asset_upload_jobs/up.sql b/migrations/2021-05-15-071545_asset_upload_jobs/up.sql index eeeed7f44f..63da573ff0 100644 --- a/migrations/2021-05-15-071545_asset_upload_jobs/up.sql +++ b/migrations/2021-05-15-071545_asset_upload_jobs/up.sql @@ -5,6 +5,9 @@ CREATE TABLE tts_model_upload_jobs ( id BIGINT(20) NOT NULL AUTO_INCREMENT, + -- Idempotency token + uuid_idempotency_token VARCHAR(36) NOT NULL, + -- Foreign key to user creator_user_token VARCHAR(32) NOT NULL, @@ -85,6 +88,7 @@ CREATE TABLE tts_model_upload_jobs ( -- INDICES -- PRIMARY KEY (id), + UNIQUE KEY (uuid_idempotency_token), KEY fk_creator_user_token (creator_user_token), KEY fk_maybe_subject_token (maybe_subject_token), KEY fk_maybe_actor_subject_token (maybe_actor_subject_token), @@ -97,7 +101,10 @@ CREATE TABLE tts_model_upload_jobs ( CREATE TABLE w2l_template_upload_jobs ( id BIGINT(20) NOT NULL AUTO_INCREMENT, - -- Foreign key to user + -- Idempotency token + uuid_idempotency_token VARCHAR(36) NOT NULL, + + -- Foreign key to user creator_user_token VARCHAR(32) NOT NULL, -- For abuse tracking. @@ -174,6 +181,7 @@ CREATE TABLE w2l_template_upload_jobs ( -- INDICES -- PRIMARY KEY (id), + UNIQUE KEY (uuid_idempotency_token), KEY fk_creator_user_token (creator_user_token), KEY fk_maybe_subject_token (maybe_subject_token), KEY fk_maybe_actor_subject_token (maybe_actor_subject_token), diff --git a/src/endpoints/tts/enqueue_upload_tts_model.rs b/src/endpoints/tts/enqueue_upload_tts_model.rs index de0068a435..3775dddebb 100644 --- a/src/endpoints/tts/enqueue_upload_tts_model.rs +++ b/src/endpoints/tts/enqueue_upload_tts_model.rs @@ -24,6 +24,7 @@ const NEW_USER_ROLE: &'static str = "new-user"; #[derive(Deserialize)] pub struct UploadTtsModelRequest { + idempotency_token: String, title: String, download_url: String, download_url_type: Option, @@ -105,12 +106,17 @@ pub async fn upload_tts_model_handler( } }; + if let Err(reason) = validate_idempotency_token(&request.idempotency_token) { + return Err(UploadTtsModelError::BadInput(reason)); + } + if let Err(reason) = validate_model_title(&request.title) { return Err(UploadTtsModelError::BadInput(reason)); } let ip_address = get_request_ip(&http_request); + let uuid = request.idempotency_token.to_string(); let title = request.title.to_string(); let download_url = request.download_url.to_string(); @@ -124,6 +130,7 @@ pub async fn upload_tts_model_handler( r#" INSERT INTO tts_model_upload_jobs SET + uuid_idempotency_token = ?, creator_user_token = ?, creator_ip_address = ?, creator_set_visibility = ?, @@ -135,6 +142,7 @@ SET download_url_type = ?, status = "pending" "#, + uuid.to_string(), user_session.user_token.to_string(), ip_address.to_string(), creator_set_visibility.to_string(), @@ -190,3 +198,11 @@ SET .content_type("application/json") .body(body)) } + +fn validate_idempotency_token(token: &str) -> Result<(), String> { + if token.len() != 36 { + return Err("idempotency token should be 36 characters".to_string()); + } + + Ok(()) +} diff --git a/src/endpoints/w2l/enqueue_upload_w2l_template.rs b/src/endpoints/w2l/enqueue_upload_w2l_template.rs index 9872755af6..9b57b2533e 100644 --- a/src/endpoints/w2l/enqueue_upload_w2l_template.rs +++ b/src/endpoints/w2l/enqueue_upload_w2l_template.rs @@ -24,6 +24,7 @@ const NEW_USER_ROLE: &'static str = "new-user"; #[derive(Deserialize)] pub struct UploadW2lTemplateRequest { + idempotency_token: String, title: String, download_url: String, download_url_type: Option, @@ -105,12 +106,17 @@ pub async fn upload_w2l_template_handler( } }; + if let Err(reason) = validate_idempotency_token(&request.idempotency_token) { + return Err(UploadW2lTemplateError::BadInput(reason)); + } + if let Err(reason) = validate_model_title(&request.title) { return Err(UploadW2lTemplateError::BadInput(reason)); } let ip_address = get_request_ip(&http_request); + let uuid = request.idempotency_token.to_string(); let title = request.title.to_string(); let download_url = request.download_url.to_string(); @@ -124,6 +130,7 @@ pub async fn upload_w2l_template_handler( r#" INSERT INTO w2l_template_upload_jobs SET + uuid_idempotency_token = ?, creator_user_token = ?, creator_ip_address = ?, creator_set_visibility = ?, @@ -135,6 +142,7 @@ SET download_url_type = ?, status = "pending" "#, + uuid.to_string(), user_session.user_token.to_string(), ip_address.to_string(), creator_set_visibility.to_string(), @@ -190,3 +198,11 @@ SET .content_type("application/json") .body(body)) } + +fn validate_idempotency_token(token: &str) -> Result<(), String> { + if token.len() != 36 { + return Err("idempotency token should be 36 characters".to_string()); + } + + Ok(()) +}