mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-04-21 12:32:38 +00:00
This way we no longer depend on the local file system path and so we can add support for cloud backends in future updates
762 lines
42 KiB
HTML
762 lines
42 KiB
HTML
{{template "base" .}}
|
|
|
|
{{define "title"}}{{.Title}}{{end}}
|
|
|
|
{{define "extra_css"}}
|
|
<link href="/static/vendor/tempusdominus/css/tempusdominus-bootstrap-4.min.css" rel="stylesheet">
|
|
{{end}}
|
|
|
|
{{define "page_body"}}
|
|
|
|
<!-- Page Heading -->
|
|
<div class="card shadow mb-4">
|
|
<div class="card-header py-3">
|
|
<h6 class="m-0 font-weight-bold text-primary">{{.Title}}</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
{{if .Error}}
|
|
<div class="card mb-4 border-left-warning">
|
|
<div class="card-body text-form-error">{{.Error}}</div>
|
|
</div>
|
|
{{end}}
|
|
{{if eq .Mode 3}}
|
|
<div class="card mb-4 border-left-info">
|
|
<div class="card-body">
|
|
Generate a data provider independent JSON file to create new users or update existing ones.
|
|
<br>
|
|
The following placeholders are supported:
|
|
<br><br>
|
|
<ul>
|
|
<li><span class="text-success">%username%</span> will be replaced with the specified username</li>
|
|
<li><span class="text-success">%password%</span> will be replaced with the specified password</li>
|
|
</ul>
|
|
The generated users file can be imported from the "Maintenance" section.
|
|
{{if .User.Username}}
|
|
<br>
|
|
Please note that no credentials were copied from user "{{.User.Username}}", you have to set them explicitly.
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
<form id="user_form" enctype="multipart/form-data" action="{{.CurrentURL}}" method="POST" autocomplete="off" {{if eq .Mode 3}}target="_blank"{{end}}>
|
|
{{if eq .Mode 3}}
|
|
<div class="form-group row">
|
|
<label for="idUsers" class="col-sm-2 col-form-label">Users</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idUsers" name="users" rows="5" required
|
|
aria-describedby="usersHelpBlock"></textarea>
|
|
<small id="usersHelpBlock" class="form-text text-muted">
|
|
Specify the username and at least one of the password and public key. Each line must be username::password::public-key
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<input type="hidden" name="username" id="idUsername" value="{{.User.Username}}">
|
|
{{else}}
|
|
<div class="form-group row">
|
|
<label for="idUsername" class="col-sm-2 col-form-label">Username</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idUsername" name="username" placeholder=""
|
|
value="{{.User.Username}}" maxlength="255" autocomplete="nope" required {{if ge .Mode 2}}readonly{{end}}>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="form-group row">
|
|
<label for="idStatus" class="col-sm-2 col-form-label">Status</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idStatus" name="status">
|
|
<option value="1" {{if eq .User.Status 1 }}selected{{end}}>Active</option>
|
|
<option value="0" {{if eq .User.Status 0 }}selected{{end}}>Inactive</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idExpirationDate" class="col-sm-2 col-form-label">Expiration Date</label>
|
|
<div class="col-sm-10 input-group date" id="expirationDatePicker" data-target-input="nearest">
|
|
<input type="text" class="form-control datetimepicker-input" id="idExpirationDate"
|
|
data-target="#expirationDatePicker">
|
|
<div class="input-group-append" data-target="#expirationDatePicker" data-toggle="datetimepicker">
|
|
<div class="input-group-text"><i class="fas fa-calendar"></i></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{if ne .Mode 3}}
|
|
<div class="form-group row">
|
|
<label for="idPassword" class="col-sm-2 col-form-label">Password</label>
|
|
<div class="col-sm-10">
|
|
<input type="password" class="form-control" id="idPassword" name="password" placeholder="" {{if eq .Mode 2}}aria-describedby="pwdHelpBlock" {{end}}>
|
|
{{if eq .Mode 2}}
|
|
<small id="pwdHelpBlock" class="form-text text-muted">
|
|
If empty the current password will not be changed
|
|
</small>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idPublicKeys" class="col-sm-2 col-form-label">Public keys</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idPublicKeys" name="public_keys" rows="3"
|
|
aria-describedby="pkHelpBlock">{{range .User.PublicKeys}}{{.}} {{end}}</textarea>
|
|
<small id="pkHelpBlock" class="form-text text-muted">
|
|
One public key or SSH user certificate per line
|
|
</small>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
<div class="form-group row">
|
|
<label for="idProtocols" class="col-sm-2 col-form-label">Denied protocols</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idProtocols" name="denied_protocols" multiple>
|
|
{{range $protocol := .ValidProtocols}}
|
|
<option value="{{$protocol}}" {{range $p :=$.User.Filters.DeniedProtocols }}{{if eq $p $protocol}}selected{{end}}{{end}}>{{$protocol}}
|
|
</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idLoginMethods" class="col-sm-2 col-form-label">Denied login methods</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idLoginMethods" name="ssh_login_methods" multiple>
|
|
{{range $method := .ValidSSHLoginMethods}}
|
|
<option value="{{$method}}" {{range $m :=$.User.Filters.DeniedLoginMethods }}{{if eq $m $method}}selected{{end}}{{end}}>{{$method}}
|
|
</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idPermissions" class="col-sm-2 col-form-label">Permissions</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idPermissions" name="permissions" required multiple>
|
|
{{range $validPerm := .ValidPerms}}
|
|
<option value="{{$validPerm}}" {{range $perm :=$.RootDirPerms }}{{if eq $perm $validPerm}}selected{{end}}{{end}}>{{$validPerm}}
|
|
</option>
|
|
{{end}}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idSubDirsPermissions" class="col-sm-2 col-form-label">Sub dirs permissions</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idSubDirsPermissions" name="sub_dirs_permissions" rows="3"
|
|
aria-describedby="subDirsHelpBlock">{{range $dir, $perms := .User.Permissions -}}
|
|
{{if ne $dir "/" -}}
|
|
{{$dir}}::{{range $index, $p := $perms}}{{if $index}},{{end}}{{$p}}{{end}}
|
|
{{- end}}
|
|
{{- end}}</textarea>
|
|
<small id="subDirsHelpBlock" class="form-text text-muted">
|
|
One exposed virtual directory path per line as /dir::perms, for example /somedir::list,download
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idHomeDir" class="col-sm-2 col-form-label">Home Dir</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idHomeDir" name="home_dir" placeholder=""
|
|
value="{{.User.HomeDir}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idVirtualFolders" class="col-sm-2 col-form-label">Virtual folders</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idVirtualFolders" name="virtual_folders" rows="3"
|
|
aria-describedby="vfHelpBlock">{{range $index, $mapping := .User.VirtualFolders -}}
|
|
{{$mapping.VirtualPath}}::{{$mapping.Name}}::{{$mapping.QuotaFiles}}::{{$mapping.QuotaSize}}
|
|
{{- end}}</textarea>
|
|
<small id="vfHelpBlock" class="form-text text-muted">
|
|
One mapping per line as vpath::folder-name::[quota_files]::[quota_size(bytes)], for example
|
|
/vdir::afolder or /vdir::afolder::10::104857600. Quota -1 means included inside user quota.
|
|
Ignored for non local filesystems
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idQuotaFiles" class="col-sm-2 col-form-label">Quota files</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idQuotaFiles" name="quota_files" placeholder=""
|
|
value="{{.User.QuotaFiles}}" min="0" aria-describedby="qfHelpBlock">
|
|
<small id="qfHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idQuotaSize" class="col-sm-2 col-form-label">Quota size (bytes)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idQuotaSize" name="quota_size" placeholder=""
|
|
value="{{.User.QuotaSize}}" min="0" aria-describedby="qsHelpBlock">
|
|
<small id="qsHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idMaxUploadSize" class="col-sm-2 col-form-label">Max file upload size (bytes)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idMaxUploadSize" name="max_upload_file_size"
|
|
placeholder="" value="{{.User.Filters.MaxUploadFileSize}}" min="0"
|
|
aria-describedby="fqsHelpBlock">
|
|
<small id="fqsHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idMaxSessions" class="col-sm-2 col-form-label">Max sessions</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idMaxSessions" name="max_sessions" placeholder=""
|
|
value="{{.User.MaxSessions}}" min="0" aria-describedby="sessionsHelpBlock">
|
|
<small id="sessionsHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idUploadBandwidth" class="col-sm-2 col-form-label">Bandwidth UL (KB/s)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idUploadBandwidth" name="upload_bandwidth"
|
|
placeholder="" value="{{.User.UploadBandwidth}}" min="0" aria-describedby="ulHelpBlock">
|
|
<small id="ulHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idDownloadBandwidth" class="col-sm-2 col-form-label">Bandwidth DL (KB/s)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idDownloadBandwidth" name="download_bandwidth"
|
|
placeholder="" value="{{.User.DownloadBandwidth}}" min="0" aria-describedby="dlHelpBlock">
|
|
<small id="dlHelpBlock" class="form-text text-muted">
|
|
0 means no limit
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idUID" class="col-sm-2 col-form-label">UID</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idUID" name="uid" placeholder="" value="{{.User.UID}}"
|
|
min="0" max="65535">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idGID" class="col-sm-2 col-form-label">GID</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idGID" name="gid" placeholder="" value="{{.User.GID}}"
|
|
min="0" max="65535">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idDeniedIP" class="col-sm-2 col-form-label">Denied IP/Mask</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idDeniedIP" name="denied_ip" placeholder=""
|
|
value="{{.User.GetDeniedIPAsString}}" maxlength="255" aria-describedby="deniedIPHelpBlock">
|
|
<small id="deniedIPHelpBlock" class="form-text text-muted">
|
|
Comma separated IP/Mask in CIDR format, for example "192.168.1.0/24,10.8.0.100/32"
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idAllowedIP" class="col-sm-2 col-form-label">Allowed IP/Mask</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idAllowedIP" name="allowed_ip" placeholder=""
|
|
value="{{.User.GetAllowedIPAsString}}" maxlength="255" aria-describedby="allowedIPHelpBlock">
|
|
<small id="allowedIPHelpBlock" class="form-text text-muted">
|
|
Comma separated IP/Mask in CIDR format, for example "192.168.1.0/24,10.8.0.100/32"
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idFilePatternsDenied" class="col-sm-2 col-form-label">Denied file patterns</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idFilePatternsDenied" name="denied_patterns" rows="3"
|
|
aria-describedby="deniedPatternsHelpBlock">{{range $index, $filter := .User.Filters.FilePatterns -}}
|
|
{{if $filter.DeniedPatterns -}}
|
|
{{$filter.Path}}::{{range $idx, $p := $filter.DeniedPatterns}}{{if $idx}},{{end}}{{$p}}{{end}}
|
|
{{- end}}
|
|
{{- end}}</textarea>
|
|
<small id="deniedPatternsHelpBlock" class="form-text text-muted">
|
|
One exposed virtual directory per line as /dir::pattern1,pattern2, for example
|
|
/subdir::*.zip,*.rar
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idFilePatternsAllowed" class="col-sm-2 col-form-label">Allowed file patterns</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idFilePatternsAllowed" name="allowed_patterns" rows="3"
|
|
aria-describedby="allowedPatternsHelpBlock">{{range $index, $filter := .User.Filters.FilePatterns -}}
|
|
{{if $filter.AllowedPatterns -}}
|
|
{{$filter.Path}}::{{range $idx, $p := $filter.AllowedPatterns}}{{if $idx}},{{end}}{{$p}}{{end}}
|
|
{{- end}}
|
|
{{- end}}</textarea>
|
|
<small id="allowedPatternsHelpBlock" class="form-text text-muted">
|
|
One exposed virtual directory per line as /dir::pattern1,pattern2, for example
|
|
/somedir::*.jpg,*.png
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idFilesExtensionsDenied" class="col-sm-2 col-form-label">Denied file extensions</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idFilesExtensionsDenied" name="denied_extensions" rows="3"
|
|
aria-describedby="deniedExtensionsHelpBlock">{{range $index, $filter := .User.Filters.FileExtensions -}}
|
|
{{if $filter.DeniedExtensions -}}
|
|
{{$filter.Path}}::{{range $idx, $p := $filter.DeniedExtensions}}{{if $idx}},{{end}}{{$p}}{{end}}
|
|
{{- end}}
|
|
{{- end}}</textarea>
|
|
<small id="deniedExtensionsHelpBlock" class="form-text text-muted">
|
|
One exposed virtual directory per line as /dir::extension1,extension2, for example
|
|
/subdir::.zip,.rar. Deprecated, use file patterns
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idFilesExtensionsAllowed" class="col-sm-2 col-form-label">Allowed file extensions</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idFilesExtensionsAllowed" name="allowed_extensions" rows="3"
|
|
aria-describedby="allowedExtensionsHelpBlock">{{range $index, $filter := .User.Filters.FileExtensions -}}
|
|
{{if $filter.AllowedExtensions -}}
|
|
{{$filter.Path}}::{{range $idx, $p := $filter.AllowedExtensions}}{{if $idx}},{{end}}{{$p}}{{end}}
|
|
{{- end}}
|
|
{{- end}}</textarea>
|
|
<small id="allowedExtensionsHelpBlock" class="form-text text-muted">
|
|
One exposed virtual directory per line as /dir::extension1,extension2, for example
|
|
/somedir::.jpg,.png. Deprecated, use file patterns
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idFilesystem" class="col-sm-2 col-form-label">Storage</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idFilesystem" name="fs_provider"
|
|
onchange="onFilesystemChanged(this.value)">
|
|
<option value="0" {{if eq .User.FsConfig.Provider 0 }}selected{{end}}>Local</option>
|
|
<option value="4" {{if eq .User.FsConfig.Provider 4 }}selected{{end}}>Local encrypted</option>
|
|
<option value="1" {{if eq .User.FsConfig.Provider 1 }}selected{{end}}>AWS S3 (Compatible)</option>
|
|
<option value="2" {{if eq .User.FsConfig.Provider 2 }}selected{{end}}>Google Cloud Storage</option>
|
|
<option value="3" {{if eq .User.FsConfig.Provider 3 }}selected{{end}}>Azure Blob Storage</option>
|
|
<option value="5" {{if eq .User.FsConfig.Provider 5 }}selected{{end}}>SFTP</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3Bucket" class="col-sm-2 col-form-label">Bucket</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3Bucket" name="s3_bucket" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.Bucket}}" maxlength="255">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idS3Region" class="col-sm-2 col-form-label">Region</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3Region" name="s3_region" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.Region}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3AccessKey" class="col-sm-2 col-form-label">Access Key</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3AccessKey" name="s3_access_key" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.AccessKey}}" maxlength="255">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idS3AccessSecret" class="col-sm-2 col-form-label">Access Secret</label>
|
|
<div class="col-sm-3">
|
|
<input type="password" class="form-control" id="idS3AccessSecret" name="s3_access_secret"
|
|
placeholder=""
|
|
value="{{if .User.FsConfig.S3Config.AccessSecret.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.S3Config.AccessSecret.GetPayload}}{{end}}"
|
|
maxlength="1000">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3StorageClass" class="col-sm-2 col-form-label">Storage Class</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3StorageClass" name="s3_storage_class" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.StorageClass}}" maxlength="255">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idS3Endpoint" class="col-sm-2 col-form-label">Endpoint</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idS3Endpoint" name="s3_endpoint" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.Endpoint}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3PartSize" class="col-sm-2 col-form-label">UL Part Size (MB)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idS3PartSize" name="s3_upload_part_size"
|
|
placeholder="" value="{{.User.FsConfig.S3Config.UploadPartSize}}"
|
|
aria-describedby="S3PartSizeHelpBlock">
|
|
<small id="S3PartSizeHelpBlock" class="form-text text-muted">
|
|
The buffer size for multipart uploads. Zero means the default (5 MB). Minimum is 5
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idS3UploadConcurrency" class="col-sm-2 col-form-label">UL Concurrency</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idS3UploadConcurrency" name="s3_upload_concurrency"
|
|
placeholder="" value="{{.User.FsConfig.S3Config.UploadConcurrency}}" min="0"
|
|
aria-describedby="S3ConcurrencyHelpBlock">
|
|
<small id="S3ConcurrencyHelpBlock" class="form-text text-muted">
|
|
How many parts are uploaded in parallel. Zero means the default (2)
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row s3">
|
|
<label for="idS3KeyPrefix" class="col-sm-2 col-form-label">Key Prefix</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idS3KeyPrefix" name="s3_key_prefix" placeholder=""
|
|
value="{{.User.FsConfig.S3Config.KeyPrefix}}" maxlength="255"
|
|
aria-describedby="S3KeyPrefixHelpBlock">
|
|
<small id="S3KeyPrefixHelpBlock" class="form-text text-muted">
|
|
Similar to a chroot for local filesystem. Cannot start with "/". Example: "somedir/subdir/".
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row gcs">
|
|
<label for="idGCSBucket" class="col-sm-2 col-form-label">Bucket</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idGCSBucket" name="gcs_bucket" placeholder=""
|
|
value="{{.User.FsConfig.GCSConfig.Bucket}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row gcs">
|
|
<label for="idGCSCredentialFile" class="col-sm-2 col-form-label">Credentials file</label>
|
|
<div class="col-sm-4">
|
|
<input type="file" class="form-control-file" id="idGCSCredentialFile" name="gcs_credential_file"
|
|
aria-describedby="GCSCredentialsHelpBlock">
|
|
<small id="GCSCredentialsHelpBlock" class="form-text text-muted">
|
|
Add or update credentials from a JSON file
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-1"></div>
|
|
<label for="idGCSStorageClass" class="col-sm-2 col-form-label">Storage Class</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idGCSStorageClass" name="gcs_storage_class"
|
|
placeholder="" value="{{.User.FsConfig.GCSConfig.StorageClass}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group gcs">
|
|
<div class="form-check">
|
|
<input type="checkbox" class="form-check-input" id="idGCSAutoCredentials"
|
|
name="gcs_auto_credentials" {{if gt .User.FsConfig.GCSConfig.AutomaticCredentials 0}}checked{{end}}>
|
|
<label for="idGCSAutoCredentials" class="form-check-label">Automatic credentials</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row gcs">
|
|
<label for="idGCSKeyPrefix" class="col-sm-2 col-form-label">Key Prefix</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idGCSKeyPrefix" name="gcs_key_prefix" placeholder=""
|
|
value="{{.User.FsConfig.GCSConfig.KeyPrefix}}" maxlength="255"
|
|
aria-describedby="GCSKeyPrefixHelpBlock">
|
|
<small id="GCSKeyPrefixHelpBlock" class="form-text text-muted">
|
|
Similar to a chroot for local filesystem. Cannot start with "/". Example: "somedir/subdir/".
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row azblob">
|
|
<label for="idAzContainer" class="col-sm-2 col-form-label">Container</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idAzContainer" name="az_container" placeholder=""
|
|
value="{{.User.FsConfig.AzBlobConfig.Container}}" maxlength="255">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idAzAccountName" class="col-sm-2 col-form-label">Account Name</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idAzAccountName" name="az_account_name" placeholder=""
|
|
value="{{.User.FsConfig.AzBlobConfig.AccountName}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row azblob">
|
|
<label for="idAzAccountKey" class="col-sm-2 col-form-label">Account Key</label>
|
|
<div class="col-sm-10">
|
|
<input type="password" class="form-control" id="idAzAccountKey" name="az_account_key" placeholder=""
|
|
value="{{if .User.FsConfig.AzBlobConfig.AccountKey.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.AzBlobConfig.AccountKey.GetPayload}}{{end}}"
|
|
maxlength="1000">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row azblob">
|
|
<label for="idAzSASURL" class="col-sm-2 col-form-label">SAS URL</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idAzSASURL" name="az_sas_url" placeholder=""
|
|
value="{{.User.FsConfig.AzBlobConfig.SASURL}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
<div class="form-group row azblob">
|
|
<label for="idAzEndpoint" class="col-sm-2 col-form-label">Endpoint</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idAzEndpoint" name="az_endpoint" placeholder=""
|
|
value="{{.User.FsConfig.AzBlobConfig.Endpoint}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row azblob">
|
|
<label for="idAzAccessTier" class="col-sm-2 col-form-label">Access Tier</label>
|
|
<div class="col-sm-10">
|
|
<select class="form-control" id="idAzAccessTier" name="az_access_tier">
|
|
<option value="" {{if eq .User.FsConfig.AzBlobConfig.AccessTier "" }}selected{{end}}>Default</option>
|
|
<option value="Hot" {{if eq .User.FsConfig.AzBlobConfig.AccessTier "Hot" }}selected{{end}}>Hot</option>
|
|
<option value="Cool" {{if eq .User.FsConfig.AzBlobConfig.AccessTier "Cool" }}selected{{end}}>Cool</option>
|
|
<option value="Archive" {{if eq .User.FsConfig.AzBlobConfig.AccessTier "Archive"}}selected{{end}}>Archive</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row azblob">
|
|
<label for="idAzPartSize" class="col-sm-2 col-form-label">UL Part Size (MB)</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idAzPartSize" name="az_upload_part_size"
|
|
placeholder="" value="{{.User.FsConfig.AzBlobConfig.UploadPartSize}}"
|
|
aria-describedby="AzPartSizeHelpBlock">
|
|
<small id="AzPartSizeHelpBlock" class="form-text text-muted">
|
|
The buffer size for multipart uploads. Zero means the default (4 MB)
|
|
</small>
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idAzUploadConcurrency" class="col-sm-2 col-form-label">UL Concurrency</label>
|
|
<div class="col-sm-3">
|
|
<input type="number" class="form-control" id="idAzUploadConcurrency" name="az_upload_concurrency"
|
|
placeholder="" value="{{.User.FsConfig.AzBlobConfig.UploadConcurrency}}" min="0"
|
|
aria-describedby="AzConcurrencyHelpBlock">
|
|
<small id="AzConcurrencyHelpBlock" class="form-text text-muted">
|
|
How many parts are uploaded in parallel. Zero means the default (2)
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row azblob">
|
|
<label for="idAzKeyPrefix" class="col-sm-2 col-form-label">Key Prefix</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idAzKeyPrefix" name="az_key_prefix" placeholder=""
|
|
value="{{.User.FsConfig.AzBlobConfig.KeyPrefix}}" maxlength="255"
|
|
aria-describedby="AzKeyPrefixHelpBlock">
|
|
<small id="AzKeyPrefixHelpBlock" class="form-text text-muted">
|
|
Similar to a chroot for local filesystem. Cannot start with "/". Example: "somedir/subdir/".
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group azblob">
|
|
<div class="form-check">
|
|
<input type="checkbox" class="form-check-input" id="idUseEmulator" name="az_use_emulator" {{if .User.FsConfig.AzBlobConfig.UseEmulator}}checked{{end}}>
|
|
<label for="idUseEmulator" class="form-check-label">Use Azure Blob emulator</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row crypt">
|
|
<label for="idCryptPassphrase" class="col-sm-2 col-form-label">Passphrase</label>
|
|
<div class="col-sm-10">
|
|
<input type="password" class="form-control" id="idCryptPassphrase" name="crypt_passphrase"
|
|
placeholder=""
|
|
value="{{if .User.FsConfig.CryptConfig.Passphrase.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.CryptConfig.Passphrase.GetPayload}}{{end}}"
|
|
maxlength="1000">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row sftp">
|
|
<label for="idSFTPEndpoint" class="col-sm-2 col-form-label">Endpoint</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idSFTPEndpoint" name="sftp_endpoint" placeholder=""
|
|
value="{{.User.FsConfig.SFTPConfig.Endpoint}}" maxlength="255">
|
|
</div>
|
|
<div class="col-sm-2"></div>
|
|
<label for="idSFTPUsername" class="col-sm-2 col-form-label">Username</label>
|
|
<div class="col-sm-3">
|
|
<input type="text" class="form-control" id="idSFTPUsername" name="sftp_username" placeholder=""
|
|
value="{{.User.FsConfig.SFTPConfig.Username}}" maxlength="255">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row sftp">
|
|
<label for="idSFTPPassword" class="col-sm-2 col-form-label">Password</label>
|
|
<div class="col-sm-10">
|
|
<input type="password" class="form-control" id="idSFTPPassword" name="sftp_password" placeholder=""
|
|
value="{{if .User.FsConfig.SFTPConfig.Password.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.SFTPConfig.Password.GetPayload}}{{end}}"
|
|
maxlength="1000">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row sftp">
|
|
<label for="idSFTPPrivateKey" class="col-sm-2 col-form-label">Private key</label>
|
|
<div class="col-sm-10">
|
|
<textarea type="password" class="form-control" id="idSFTPPrivateKey" name="sftp_private_key"
|
|
rows="3">{{if .User.FsConfig.SFTPConfig.PrivateKey.IsEncrypted}}{{.RedactedSecret}}{{else}}{{.User.FsConfig.SFTPConfig.PrivateKey.GetPayload}}{{end}}</textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row sftp">
|
|
<label for="idSFTPFingerprints" class="col-sm-2 col-form-label">Fingerprints</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idSFTPFingerprints" name="sftp_fingerprints" rows="3"
|
|
aria-describedby="SFTPFingerprintsHelpBlock">{{range .User.FsConfig.SFTPConfig.Fingerprints}}{{.}} {{end}}</textarea>
|
|
<small id="SFTPFingerprintsHelpBlock" class="form-text text-muted">
|
|
SHA256 fingerprints to validate when connecting to the external SFTP server, one per line. If
|
|
empty any host key will be accepted: this is a security risk!
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row sftp">
|
|
<label for="idSFTPPrefix" class="col-sm-2 col-form-label">Prefix</label>
|
|
<div class="col-sm-10">
|
|
<input type="text" class="form-control" id="idSFTPPrefix" name="sftp_prefix" placeholder=""
|
|
value="{{.User.FsConfig.SFTPConfig.Prefix}}" maxlength="255"
|
|
aria-describedby="SFTPPrefixHelpBlock">
|
|
<small id="SFTPPrefixHelpBlock" class="form-text text-muted">
|
|
Similar to a chroot for local filesystem. Example: "/somedir/subdir".
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group row">
|
|
<label for="idAdditionalInfo" class="col-sm-2 col-form-label">Additional info</label>
|
|
<div class="col-sm-10">
|
|
<textarea class="form-control" id="idAdditionalInfo" name="additional_info" rows="3"
|
|
aria-describedby="additionalInfoHelpBlock">{{.User.AdditionalInfo}}</textarea>
|
|
<small id="additionalInfoHelpBlock" class="form-text text-muted">
|
|
Free form text field
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
{{if eq .Mode 2}}
|
|
<div class="form-group">
|
|
<div class="form-check">
|
|
<input type="checkbox" class="form-check-input" id="idDisconnect" name="disconnect"
|
|
aria-describedby="disconnectHelpBlock">
|
|
<label for="idDisconnect" class="form-check-label">Disconnect the user after the update</label>
|
|
<small id="disconnectHelpBlock" class="form-text text-muted">
|
|
This way you force the user to login again, if connected, and so to use the new configuration
|
|
</small>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<input type="hidden" name="expiration_date" id="hidden_start_datetime" value="">
|
|
<button type="submit" class="btn btn-primary float-right mt-3 px-5 px-3">{{if eq .Mode 3}}Generate and export users{{else}}Submit{{end}}</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{define "extra_js"}}
|
|
<script src="/static/vendor/moment/js/moment.min.js"></script>
|
|
<script src="/static/vendor/tempusdominus/js/tempusdominus-bootstrap-4.min.js"></script>
|
|
<script type="text/javascript">
|
|
$(document).ready(function () {
|
|
|
|
$('#expirationDatePicker').datetimepicker({
|
|
format: 'YYYY-MM-DD',
|
|
buttons: {
|
|
showClear: false,
|
|
showClose: true,
|
|
showToday: false
|
|
}
|
|
});
|
|
|
|
{{ if gt .User.ExpirationDate 0 }}
|
|
var input_dt = moment({{.User.ExpirationDate }}).format('YYYY-MM-DD');
|
|
$('#idExpirationDate').val(input_dt);
|
|
$('#expirationDatePicker').datetimepicker('viewDate', input_dt);
|
|
{{ end }}
|
|
|
|
$("#user_form").submit(function (event) {
|
|
var dt = $('#idExpirationDate').val();
|
|
if (dt) {
|
|
var d = $('#expirationDatePicker').datetimepicker('viewDate');
|
|
if (d) {
|
|
var dateString = moment(d).format('YYYY-MM-DD HH:mm:ss');
|
|
$('#hidden_start_datetime').val(dateString);
|
|
} else {
|
|
$('#hidden_start_datetime').val("");
|
|
}
|
|
} else {
|
|
$('#hidden_start_datetime').val("");
|
|
}
|
|
return true;
|
|
});
|
|
|
|
onFilesystemChanged('{{.User.FsConfig.Provider}}');
|
|
|
|
});
|
|
|
|
function onFilesystemChanged(val){
|
|
if (val == '1'){
|
|
$('.form-group.row.gcs').hide();
|
|
$('.form-group.gcs').hide();
|
|
$('.form-group.row.azblob').hide();
|
|
$('.form-group.azblob').hide();
|
|
$('.form-group.crypt').hide();
|
|
$('.form-group.sftp').hide();
|
|
$('.form-group.row.s3').show();
|
|
} else if (val == '2'){
|
|
$('.form-group.row.gcs').show();
|
|
$('.form-group.gcs').show();
|
|
$('.form-group.row.azblob').hide();
|
|
$('.form-group.azblob').hide();
|
|
$('.form-group.crypt').hide();
|
|
$('.form-group.row.s3').hide();
|
|
$('.form-group.sftp').hide();
|
|
} else if (val == '3'){
|
|
$('.form-group.row.azblob').show();
|
|
$('.form-group.azblob').show();
|
|
$('.form-group.row.gcs').hide();
|
|
$('.form-group.gcs').hide();
|
|
$('.form-group.crypt').hide();
|
|
$('.form-group.row.s3').hide();
|
|
$('.form-group.sftp').hide();
|
|
} else if (val == '4'){
|
|
$('.form-group.row.gcs').hide();
|
|
$('.form-group.gcs').hide();
|
|
$('.form-group.row.s3').hide();
|
|
$('.form-group.row.azblob').hide();
|
|
$('.form-group.azblob').hide();
|
|
$('.form-group.crypt').show();
|
|
$('.form-group.sftp').hide();
|
|
} else if (val == '5'){
|
|
$('.form-group.row.gcs').hide();
|
|
$('.form-group.gcs').hide();
|
|
$('.form-group.row.s3').hide();
|
|
$('.form-group.row.azblob').hide();
|
|
$('.form-group.azblob').hide();
|
|
$('.form-group.crypt').hide();
|
|
$('.form-group.sftp').show();
|
|
} else {
|
|
$('.form-group.row.gcs').hide();
|
|
$('.form-group.gcs').hide();
|
|
$('.form-group.row.s3').hide();
|
|
$('.form-group.row.azblob').hide();
|
|
$('.form-group.azblob').hide();
|
|
$('.form-group.crypt').hide();
|
|
$('.form-group.sftp').hide();
|
|
}
|
|
}
|
|
</script>
|
|
{{end}}
|