Compare commits
5 Commits
e81a5e3ec3
...
262f6a439a
Author | SHA1 | Date |
---|---|---|
blek | 262f6a439a | |
blek | b82e630b65 | |
blek | c8e7a66398 | |
blek | bdc9a89331 | |
blek | 5b3bae7892 |
|
@ -21,6 +21,11 @@ allow_pass_protection=true
|
|||
# This is shown only if allow_uploads = false
|
||||
# upload_disable_reason="File uploads were disabled because of an ongoing attack."
|
||||
|
||||
# If you want to restrict the uploads
|
||||
# To only the people who have a password,
|
||||
# uncomment this field
|
||||
# upload_pass=super_secret_pass
|
||||
|
||||
# Timeout for deleting a user uploaded file
|
||||
file_del_timeout=1800
|
||||
|
||||
|
|
|
@ -111,6 +111,10 @@ paths:
|
|||
type: string
|
||||
example: binary file data
|
||||
description: binary file data
|
||||
instance_pass:
|
||||
type: string
|
||||
example: super_secret_pass
|
||||
description: Instance-specific password needed to upload files
|
||||
metadata:
|
||||
type: object
|
||||
description: file info
|
||||
|
|
|
@ -22,6 +22,10 @@ pub struct FilesPolicy {
|
|||
#[serde(default)]
|
||||
pub upload_disable_reason: Option<String>,
|
||||
|
||||
/// Upload password
|
||||
#[serde(default)]
|
||||
pub upload_pass: Option<String>,
|
||||
|
||||
/// Default time for file to be deleted
|
||||
#[serde(default)]
|
||||
pub file_del_timeout: usize,
|
||||
|
@ -42,6 +46,7 @@ impl Default for FilesPolicy {
|
|||
allow_custom_names: true,
|
||||
allow_pass_protection: true,
|
||||
upload_disable_reason: None,
|
||||
upload_pass: None,
|
||||
file_del_timeout: 1800,
|
||||
type_whitelist: None,
|
||||
type_blacklist: None,
|
||||
|
|
|
@ -61,6 +61,7 @@ impl FormElement {
|
|||
struct UploadFormData {
|
||||
filename: Option<String>,
|
||||
password: Option<String>,
|
||||
instancepass: Option<String>,
|
||||
lookup_kind: LookupKind,
|
||||
delmode: DeleteMode,
|
||||
file: Vec<u8>,
|
||||
|
@ -73,6 +74,7 @@ impl Default for UploadFormData {
|
|||
UploadFormData {
|
||||
filename: None,
|
||||
password: None,
|
||||
instancepass: None,
|
||||
lookup_kind: LookupKind::ByHash,
|
||||
delmode: DeleteMode::Time,
|
||||
file: vec![],
|
||||
|
@ -127,6 +129,16 @@ impl UploadFormData {
|
|||
}
|
||||
}
|
||||
|
||||
match data.get("instancepass") {
|
||||
Some(val) => {
|
||||
let val = val.data.clone();
|
||||
if let Ok(pass) = String::from_utf8(val) {
|
||||
out.instancepass = Some(pass);
|
||||
}
|
||||
},
|
||||
None => ()
|
||||
};
|
||||
|
||||
let file = data.get("file")?;
|
||||
out.file = file.data.clone();
|
||||
out.mime = file.mime.clone();
|
||||
|
@ -201,6 +213,47 @@ pub async fn upload(form: FormData, ip: Option<IpAddr>, state: SharedState) -> R
|
|||
)
|
||||
}
|
||||
|
||||
if let Some(upload_pass) = state.config.files.upload_pass.clone() {
|
||||
|
||||
if let Some(pass) = formdata.instancepass {
|
||||
if upload_pass != pass {
|
||||
let error = ErrorPage {
|
||||
env: state.env.clone(),
|
||||
conf: state.config.clone(),
|
||||
error_text: "Password is invalid".into(),
|
||||
link: Some("/".into()),
|
||||
link_text: Some("Go back".into())
|
||||
};
|
||||
|
||||
return Ok(
|
||||
Box::new(
|
||||
html(
|
||||
error.render()
|
||||
.map_err(|x| HttpReject::AskamaError(x))?
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let error = ErrorPage {
|
||||
env: state.env.clone(),
|
||||
conf: state.config.clone(),
|
||||
error_text: "Password is not available".into(),
|
||||
link: Some("/".into()),
|
||||
link_text: Some("Go back".into())
|
||||
};
|
||||
|
||||
return Ok(
|
||||
Box::new(
|
||||
html(
|
||||
error.render()
|
||||
.map_err(|x| HttpReject::AskamaError(x))?
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let file = File::create(
|
||||
formdata.file,
|
||||
formdata.mime,
|
||||
|
|
|
@ -20,4 +20,8 @@
|
|||
|
||||
.alert.danger .alert-title {
|
||||
background: #602020;
|
||||
}
|
||||
|
||||
.alert.blue .alert-title {
|
||||
background: #203050;
|
||||
}
|
|
@ -9,6 +9,31 @@
|
|||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
|
||||
{%- if conf.files.upload_pass.is_some() -%}
|
||||
|
||||
{#- Script to disable button when password is not entered -#}
|
||||
{#- -#}<script>
|
||||
{#- -#} (
|
||||
{#- -#} ()=>{
|
||||
{#- -#} const pass_inp=document.getElementById("instancepass");
|
||||
{#- -#} const submit=document.getElementById("bfile-upload-submit");
|
||||
{#- -#} submit.setAttribute('disabled',true);
|
||||
{#- -#}
|
||||
{#- -#} pass_inp.onchange=()=>{
|
||||
{#- -#} if(pass_inp.value.length==0)
|
||||
{#- -#} submit.setAttribute('disabled',true);
|
||||
{#- -#} else submit.removeAttribute('disabled')
|
||||
{#- -#} }
|
||||
{#- -#} }
|
||||
{#- -#} )()
|
||||
{#- -#}</script>
|
||||
|
||||
{%- endif -%}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div style="max-width:95vw;width:fit-content;margin:0 auto">
|
||||
|
@ -114,6 +139,24 @@
|
|||
</p>
|
||||
</div>
|
||||
{%- else -%}
|
||||
|
||||
{%- if let Some(pass) = conf.files.upload_pass -%}
|
||||
<div class="alert blue">
|
||||
<h1 class="alert-title">
|
||||
Upload password
|
||||
</h1>
|
||||
<div class="alert-text">
|
||||
<p>This instance requires a password to upload a file.</p>
|
||||
<p>
|
||||
<label>
|
||||
Password:
|
||||
<input type="password" name="instancepass" id="instancepass">
|
||||
</label>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{%- endif -%}
|
||||
|
||||
<p>
|
||||
<input type="file" name="file" id="bfile-formupload-file" style="display: none" />
|
||||
<label for="bfile-formupload-file">
|
||||
|
@ -142,7 +185,7 @@
|
|||
</label>
|
||||
</p>
|
||||
<p>
|
||||
<button class='btn btn-fill'>
|
||||
<button class='btn btn-fill' id="bfile-upload-submit">
|
||||
Upload!
|
||||
</button>
|
||||
</p>
|
||||
|
|
Loading…
Reference in New Issue