Добавлена работа с файлами. Добавлен показ изображений и загрузка файлов. Изменен дизайн
This commit is contained in:
78
html-template/file-viewer.html
Normal file
78
html-template/file-viewer.html
Normal file
@@ -0,0 +1,78 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{.Title}}</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.file-container {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.file-info {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.download-btn {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
margin: 10px;
|
||||
}
|
||||
.action-btn {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #f0f0f0;
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
margin: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="file-container">
|
||||
<h1>{{.Title}}</h1>
|
||||
|
||||
{{if .IsImage}}
|
||||
<img src="data:{{.MimeType}};base64,{{.Base64Data}}" alt="File preview">
|
||||
{{else}}
|
||||
<div class="file-info">
|
||||
<p>Этот файл не может быть отображен в браузере</p>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="file-info">
|
||||
<p><strong>Тип файла:</strong> {{.MimeType}}</p>
|
||||
<p><strong>Размер:</strong> {{.FileSize}} KB</p>
|
||||
<p><strong>Имя файла:</strong> {{.FileName}}</p>
|
||||
|
||||
<a href="data:{{.MimeType}};base64,{{.Base64Data}}"
|
||||
class="download-btn"
|
||||
download="{{.FileName}}">
|
||||
Скачать файл
|
||||
</a>
|
||||
<a href="/" class="action-btn">На главную</a>
|
||||
<a href="javascript:history.back()" class="action-btn">Назад</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
57
html-template/index-old.html
Normal file
57
html-template/index-old.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Data Unwrap Form</title>
|
||||
<style>
|
||||
textarea { width: 100%; max-width: 500px; }
|
||||
table { border-collapse: collapse; }
|
||||
hr { margin: 15px 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<!-- Форма для wrap/unwrap текста -->
|
||||
<tr><td>
|
||||
<form method="post" action="{{.URL}}/wrap">
|
||||
<table>
|
||||
<tr><td>Введите текст или токен:</td></tr>
|
||||
<tr><td>
|
||||
<textarea name="input_token" cols="50" rows="10" maxlength="{{.MAXTEXTLENGTH}}">{{.TEXT}}</textarea>
|
||||
</td></tr>
|
||||
<tr><td align="right">
|
||||
<button type="submit">Зашифровать</button>
|
||||
<button type="submit" formaction="{{.URL}}/unwrap">Расшифровать</button>
|
||||
</td></tr>
|
||||
</table>
|
||||
</form>
|
||||
</td></tr>
|
||||
|
||||
<tr><td><hr></td></tr>
|
||||
|
||||
<!-- Отдельная форма для загрузки файла -->
|
||||
<tr><td>
|
||||
<form method="post" action="{{.URL}}/wrapfile" enctype="multipart/form-data">
|
||||
<input type="file" name="file" id="file" required>
|
||||
<button type="submit">Зашифровать файл</button>
|
||||
</form>
|
||||
</td></tr>
|
||||
|
||||
<tr><td><hr></td></tr>
|
||||
|
||||
<!-- Форма для генерации пароля -->
|
||||
<tr><td>
|
||||
<form method="post" action="{{.URL}}/genpassword">
|
||||
<table>
|
||||
<tr><td align="right">
|
||||
Длина пароля (от 15 до {{.MAXTEXTLENGTH}}):
|
||||
<input type="number" name="passlength" min="15" max="{{.MAXTEXTLENGTH}}" value="32">
|
||||
<button type="submit">Сгенерировать пароль</button>
|
||||
</td></tr>
|
||||
</table>
|
||||
</form>
|
||||
</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
@@ -1,39 +1,206 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Data Unwrap Form</title>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr><td>
|
||||
<!-- <a href={{.URL}}/unwrap>Расшифровать</a> |
|
||||
<a href={{.URL}}/genpassword>Сгенерировать пароль</a>-->
|
||||
<tr><td><p></p></td></tr>
|
||||
<tr><td>
|
||||
<form method="post">
|
||||
<table>
|
||||
<tr><td>
|
||||
Введите текст или токен:
|
||||
</td></tr>
|
||||
<tr><td>
|
||||
<textarea id="wrapped_token" name="input_token" cols=50 rows=10 maxlength="{{ .MAXTEXTLENGTH }}">{{ .TEXT }}</textarea>
|
||||
</td></tr>
|
||||
<tr><td align=right>
|
||||
<!-- Время жизни токена {{.TOKENTTL}} сек.-->
|
||||
<button type="submit" formaction="{{.URL}}/wrap">Зашифровать</button>
|
||||
<button type="submit" formaction="{{.URL}}/unwrap">Расшифровать</button>
|
||||
<tr><td><hr></td></tr>
|
||||
</td></tr>
|
||||
<tr><td align=right>
|
||||
Длина пароля (от 15 до {{ .MAXTEXTLENGTH }})
|
||||
<input type="text" name="passlength"/ size=4 pattern="[0-9]{2,4}">
|
||||
<button type="submit" formaction="{{.URL}}/genpassword">Сгенерировать пароль</button>
|
||||
</td></tr>
|
||||
</form>
|
||||
</td></tr>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Data Wrap/Unwrap Form</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box; /* Добавлено */
|
||||
}
|
||||
.content {
|
||||
flex: 1;
|
||||
padding-bottom: 20px; /* Добавлено */
|
||||
}
|
||||
.form-container {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
margin-bottom: 15px; /* Уменьшено */
|
||||
}
|
||||
h1 {
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 25px; /* Уменьшено */
|
||||
font-size: 1.8em; /* Добавлено */
|
||||
}
|
||||
textarea {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-height: 120px; /* Уменьшено */
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
resize: vertical;
|
||||
box-sizing: border-box; /* Добавлено */
|
||||
}
|
||||
input[type="file"] {
|
||||
margin: 8px 0; /* Уменьшено */
|
||||
width: 100%; /* Добавлено */
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 60px;
|
||||
padding: 5px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
button {
|
||||
padding: 8px 16px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin: 4px; /* Уменьшено */
|
||||
transition: background 0.3s;
|
||||
}
|
||||
button:hover {
|
||||
background: #45a049;
|
||||
}
|
||||
hr {
|
||||
border: 0;
|
||||
height: 1px;
|
||||
background: #ddd;
|
||||
margin: 15px 0; /* Уменьшено */
|
||||
}
|
||||
.form-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 8px; /* Уменьшено */
|
||||
color: #555;
|
||||
font-size: 0.95em; /* Добавлено */
|
||||
}
|
||||
.button-group {
|
||||
text-align: right;
|
||||
margin-top: 8px; /* Уменьшено */
|
||||
}
|
||||
footer {
|
||||
text-align: center;
|
||||
padding: 12px 0;
|
||||
color: #777;
|
||||
font-size: 0.85em; /* Уменьшено */
|
||||
border-top: 1px solid #eee;
|
||||
background: white;
|
||||
margin-top: auto; /* Важно для прижатия */
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
}
|
||||
.footer-links {
|
||||
margin-top: 6px; /* Уменьшено */
|
||||
}
|
||||
.footer-links a {
|
||||
color: #4CAF50;
|
||||
text-decoration: none;
|
||||
margin: 0 6px; /* Уменьшено */
|
||||
font-size: 0.85em; /* Уменьшено */
|
||||
}
|
||||
.footer-links a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
body {
|
||||
padding: 15px;
|
||||
}
|
||||
.form-container {
|
||||
padding: 15px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
button {
|
||||
padding: 6px 12px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.btn-link {
|
||||
background: #9C27B0;
|
||||
}
|
||||
.btn-link:hover {
|
||||
background: #7B1FA2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<!-- <h1>Сервис передачи секретов</h1> -->
|
||||
|
||||
<div class="form-container">
|
||||
<div class="form-title">Введите текст или токен:</div>
|
||||
<form method="post" action="{{.URL}}/wrap">
|
||||
<textarea id="tokenTextarea" name="input_token" maxlength="{{.MAXTEXTLENGTH}}" placeholder="Введите текст или токен...">{{.TEXT}}</textarea>
|
||||
<div class="button-group">
|
||||
<button type="submit">Зашифровать</button>
|
||||
<button type="submit" formaction="{{.URL}}/unwrap">Расшифровать</button>
|
||||
<button type="button" class="btn-copy" onclick="copyToken()">Скопировать</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form-container">
|
||||
<div class="form-title">Выберите файл (до 100кб):</div>
|
||||
<form method="post" action="{{.URL}}/wrapfile" enctype="multipart/form-data">
|
||||
<input type="file" name="file" id="file" required>
|
||||
<div class="button-group">
|
||||
<button type="submit">Зашифровать файл</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="form-container">
|
||||
<div class="form-title">Генерация пароля:</div>
|
||||
<form method="post" action="{{.URL}}/genpassword">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap;">
|
||||
<div style="margin-bottom: 8px;">
|
||||
Длина пароля (от 15 до {{.MAXTEXTLENGTH}}):
|
||||
<input type="number" name="passlength" min="15" max="{{.MAXTEXTLENGTH}}" value="32">
|
||||
</div>
|
||||
<button type="submit" style="margin-left: auto;">Сгенерировать пароль</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<div>© <script>document.write(new Date().getFullYear())</script> SVK</div>
|
||||
</footer>
|
||||
|
||||
|
||||
<script>
|
||||
function copyToken() {
|
||||
const textarea = document.getElementById('tokenTextarea');
|
||||
const fullText = textarea.value;
|
||||
const token = fullText.split('\n')[0].trim();
|
||||
|
||||
copyToClipboard(token, '.btn-copy');
|
||||
}
|
||||
|
||||
function copyToClipboard(text, buttonSelector) {
|
||||
const tempInput = document.createElement('input');
|
||||
tempInput.value = text;
|
||||
document.body.appendChild(tempInput);
|
||||
tempInput.select();
|
||||
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(tempInput);
|
||||
|
||||
const copyBtn = document.querySelector(buttonSelector);
|
||||
const originalText = copyBtn.textContent;
|
||||
copyBtn.textContent = 'Скопировано!';
|
||||
|
||||
setTimeout(() => {
|
||||
copyBtn.textContent = originalText;
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
223
vault.go
223
vault.go
@@ -11,6 +11,7 @@ import (
|
||||
// "context"
|
||||
"log"
|
||||
// "time"
|
||||
"io"
|
||||
"os"
|
||||
"fmt"
|
||||
"flag"
|
||||
@@ -20,6 +21,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
"encoding/json"
|
||||
"encoding/base64"
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"html/template"
|
||||
@@ -85,15 +87,45 @@ type WrapInfo struct {
|
||||
CreationPath string `json:"creation_path"`
|
||||
}
|
||||
|
||||
type FileViewerData struct {
|
||||
Title string
|
||||
Base64Data string
|
||||
MimeType string
|
||||
FileSize string
|
||||
FileName string
|
||||
IsImage bool
|
||||
}
|
||||
// const MaxTextLength = 100
|
||||
|
||||
func vaultDataWrap(vaultAddr string, text string) string {
|
||||
secret := make(map[string]string)
|
||||
secret["wrapped_data"] = text
|
||||
|
||||
func vaultDataWrap(vaultAddr string, dataType string, content string) string {
|
||||
secret := make(map[string]string)
|
||||
// switch dataType {
|
||||
// case "text":
|
||||
// secret["wrapped_data"] = text
|
||||
// case "file":
|
||||
// secret["file"] = text
|
||||
// default:
|
||||
// secret["wrapped_data"] = text
|
||||
// }
|
||||
// Определяем ключ для данных
|
||||
if Debug {
|
||||
log.Println("Тип данныж:", dataType)
|
||||
}
|
||||
if dataType == "text" {
|
||||
// Для текста используем ключ "text"
|
||||
secret["text"] = content
|
||||
} else {
|
||||
// Для файла используем имя файла как ключ
|
||||
// Если dataType не "text" и не пустое, считаем его именем файла
|
||||
if dataType == "" {
|
||||
dataType = "file" // fallback, если имя не указано
|
||||
}
|
||||
secret[dataType] = content
|
||||
}
|
||||
|
||||
postBody, err := json.Marshal(secret)
|
||||
if err != nil {
|
||||
log.Println("Errored marshaling the text:", text)
|
||||
log.Println("Errored marshaling the text:", content)
|
||||
}
|
||||
|
||||
customTransport := &(*http.DefaultTransport.(*http.Transport))
|
||||
@@ -201,50 +233,100 @@ func getStaticPage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func showFileViewer(w http.ResponseWriter, r *http.Request, fileData []byte, fileName string) {
|
||||
// Определяем MIME-тип файла
|
||||
mimeType := http.DetectContentType(fileData)
|
||||
isImage := strings.HasPrefix(mimeType, "image/")
|
||||
|
||||
// Кодируем в base64
|
||||
base64Data := base64.StdEncoding.EncodeToString(fileData)
|
||||
|
||||
// Подготавливаем данные для шаблона
|
||||
data := FileViewerData{
|
||||
Title: "Просмотр файла",
|
||||
Base64Data: base64Data,
|
||||
MimeType: mimeType,
|
||||
FileSize: fmt.Sprintf("%.2f", float64(len(fileData))/1024),
|
||||
FileName: fileName,
|
||||
IsImage: isImage,
|
||||
}
|
||||
|
||||
// Парсим шаблон
|
||||
tmpl, err := template.ParseFiles(filepath.Join(TemplateDir, "file-viewer.html"))
|
||||
if err != nil {
|
||||
http.Error(w, "Error loading template", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Отображаем шаблон
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
err = tmpl.Execute(w, data)
|
||||
if err != nil {
|
||||
http.Error(w, "Error rendering template", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
// hvs.CAES - 95
|
||||
// s.Dj7kZS - 26
|
||||
|
||||
|
||||
func unwrapDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
token := r.FormValue("input_token")
|
||||
|
||||
vaultPath := VaultAddress + "/v1/sys/wrapping/unwrap"
|
||||
|
||||
Data = ""
|
||||
// fmt.Fprintln(w, r.URL.RawQuery)
|
||||
// log.Println(w, r.URL.RawQuery)
|
||||
if Debug {
|
||||
log.Printf("Текст для шифровки: %s ", token)
|
||||
log.Printf("Адрес сервера Hashicorp Vault: %s ", vaultPath)
|
||||
}
|
||||
// Проверка текста на соответствие шаблону
|
||||
|
||||
// Нормализация токена
|
||||
re := regexp.MustCompile(`^(hvs|s)\.[\w\-\_]+`)
|
||||
if Debug {
|
||||
fmt.Println(re.Match([]byte(token)))
|
||||
}
|
||||
token = strings.TrimSpace(strings.ReplaceAll(token, "\r\n", ""))
|
||||
|
||||
token = strings.ReplaceAll(token, "\r", "")
|
||||
token = strings.ReplaceAll(token, "\n", "")
|
||||
token = strings.ReplaceAll(token, " ", "")
|
||||
token = strings.TrimSpace(token)
|
||||
if token != "" && re.MatchString(token) {
|
||||
unwrappedData := vaultDataUnWrap(vaultPath, token)
|
||||
|
||||
// 1. Сначала проверяем наличие текстовых данных
|
||||
if textData, exists := unwrappedData["text"]; exists {
|
||||
Data = textData
|
||||
} else {
|
||||
// 2. Если текста нет, ищем файловые данные (любой ключ, кроме "text")
|
||||
var fileData []byte
|
||||
var fileName string
|
||||
|
||||
for key, value := range unwrappedData {
|
||||
if key != "text" { // Пропускаем текстовые данные, если они есть
|
||||
// Декодируем base64
|
||||
decoded, err := base64.StdEncoding.DecodeString(value)
|
||||
if err != nil {
|
||||
log.Printf("Ошибка декодирования файла %s: %v", key, err)
|
||||
continue
|
||||
}
|
||||
fileData = decoded
|
||||
fileName = key
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if token != "" && re.Match([]byte(token)) {
|
||||
b := new(bytes.Buffer)
|
||||
for key, value := range vaultDataUnWrap(vaultPath, token) {
|
||||
fmt.Fprintf(b, "%s: %s\n", key, value)
|
||||
if fileData != nil {
|
||||
// Если нашли файл - показываем просмотрщик
|
||||
showFileViewer(w, r, fileData, fileName)
|
||||
return
|
||||
} else {
|
||||
// Если не нашли ни текста, ни файла - выводим все данные как текст
|
||||
b := new(bytes.Buffer)
|
||||
for key, value := range unwrappedData {
|
||||
fmt.Fprintf(b, "%s: %s\n", key, value)
|
||||
}
|
||||
Data = b.String()
|
||||
}
|
||||
}
|
||||
Data = b.String()
|
||||
|
||||
if Data == "" {
|
||||
Data = "Ошибка! Токен не найден."
|
||||
}
|
||||
if Debug {
|
||||
log.Println(Data)
|
||||
Data = "Ошибка! Токен не содержит данных."
|
||||
}
|
||||
} else if token != "" {
|
||||
Data = "Введенные данные не соответствуют формату. Введите корректный токен."
|
||||
}
|
||||
|
||||
getStaticPage(w, r)
|
||||
// http.Redirect(w, r, "http://"+r.Host, http.StatusMovedPermanently)
|
||||
}
|
||||
|
||||
func genPassword(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -307,7 +389,7 @@ func wrapDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("Введен текст:", secret)
|
||||
}
|
||||
if secret != "" {
|
||||
Data = vaultDataWrap(vaultPath, secret)
|
||||
Data = vaultDataWrap(vaultPath, "text", secret)
|
||||
if Data == "" {
|
||||
Data = "Ошибка! Токен не найден."
|
||||
}
|
||||
@@ -325,6 +407,80 @@ func wrapDataFromHtmlForm(w http.ResponseWriter, r *http.Request) {
|
||||
getStaticPage(w, r)
|
||||
}
|
||||
|
||||
func wrapDataFromFile(w http.ResponseWriter, r *http.Request) {
|
||||
MaxFileLength := 100000 // Максимальный размер файла (100KB)
|
||||
|
||||
// 1. Проверяем метод (должен быть POST)
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// 2. Проверяем Content-Type (должен быть multipart/form-data)
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
if !strings.HasPrefix(contentType, "multipart/form-data") {
|
||||
http.Error(w, "Expected multipart/form-data", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 3. Парсим форму с ограничением размера (10 МБ)
|
||||
maxMemory := 10 << 20 // 10 MB
|
||||
if err := r.ParseMultipartForm(int64(maxMemory)); err != nil {
|
||||
log.Printf("Failed to parse multipart form: %v", err)
|
||||
http.Error(w, "Unable to parse form (file too big?)", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 4. Получаем файл из формы (включая метаданные)
|
||||
file, fileHeader, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
log.Printf("Failed to get file from form: %v", err)
|
||||
http.Error(w, "Error retrieving the file", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Получаем оригинальное имя файла
|
||||
fileName := fileHeader.Filename
|
||||
if fileName == "" {
|
||||
fileName = "unnamed_file" // Запасной вариант, если имя не указано
|
||||
}
|
||||
|
||||
if Debug {
|
||||
log.Printf("Processing file: %s (size: %d bytes)", fileName, fileHeader.Size)
|
||||
}
|
||||
|
||||
// 5. Читаем содержимое файла
|
||||
fileBytes, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
log.Printf("Failed to read file: %v", err)
|
||||
http.Error(w, "Error reading the file", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// 6. Проверяем размер файла
|
||||
if len(fileBytes) > MaxFileLength {
|
||||
errMsg := fmt.Sprintf("File too large (%d > %d)", len(fileBytes), MaxFileLength)
|
||||
http.Error(w, errMsg, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// 7. Кодируем в base64
|
||||
encoded := base64.StdEncoding.EncodeToString(fileBytes)
|
||||
|
||||
// 8. Обёртываем данные в Vault с именем файла
|
||||
vaultPath := VaultAddress + "/v1/sys/wrapping/wrap"
|
||||
token := vaultDataWrap(vaultPath, fileName, encoded)
|
||||
if token == "" {
|
||||
http.Error(w, "Failed to wrap data in Vault", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
ttl, _ := strconv.Atoi(TokenTTL)
|
||||
ttl = ttl / 3600
|
||||
Data = fmt.Sprintf("%s\n\n---\nВремя жизни токена %s ч.", token, strconv.Itoa(ttl))
|
||||
getStaticPage(w, r)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var (
|
||||
logFile string
|
||||
@@ -371,8 +527,8 @@ func main() {
|
||||
} else if os.Getenv("VAULT_TOKEN") != "" && VaultToken == "" {
|
||||
VaultToken = os.Getenv("VAULT_TOKEN")
|
||||
}
|
||||
|
||||
if os.Getenv("MAX_TEXT_LENGTH") != "" && MaxTextLength == 100 {
|
||||
|
||||
if os.Getenv("MAX_TEXT_LENGTH") != "" && MaxTextLength == 100 {
|
||||
MaxTextLength, err = strconv.Atoi(os.Getenv("MAX_TEXT_LENGTH"))
|
||||
if err != nil {
|
||||
log.Printf("Ошибка преобразования значения ", os.Getenv("MAX_TEXT_LENGTH"))
|
||||
@@ -386,6 +542,7 @@ func main() {
|
||||
rtr := mux.NewRouter()
|
||||
rtr.HandleFunc("/unwrap", unwrapDataFromHtmlForm)
|
||||
rtr.HandleFunc("/wrap", wrapDataFromHtmlForm)
|
||||
rtr.HandleFunc("/wrapfile", wrapDataFromFile).Methods("POST")
|
||||
rtr.HandleFunc("/genpassword/{passLength:[0-9]+}", genPassword)
|
||||
rtr.HandleFunc("/genpassword", genPassword)
|
||||
|
||||
|
Reference in New Issue
Block a user