commit cee408f47e0141e626263bb399289494c396ec13 Author: test Date: Sun Mar 29 20:48:36 2026 +0000 first commit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..237d763 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM golang:1.25-alpine AS builder +WORKDIR /app + +COPY go.mod go.sum ./ + +# Добавляем эту строку: +ENV GOPROXY=https://goproxy.io,direct + +RUN go mod download +COPY . . +RUN CGO_ENABLED=0 GOOS=linux go build -o main . + +FROM alpine:latest +RUN apk --no-cache add ca-certificates +WORKDIR /root/ +COPY --from=builder /app/main . +EXPOSE 8080 +CMD ["./main"] diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0708a36 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module my-auth-app + +go 1.25.0 + +require golang.org/x/crypto v0.49.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..9fd6146 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= diff --git a/main.go b/main.go new file mode 100644 index 0000000..accaf14 --- /dev/null +++ b/main.go @@ -0,0 +1,122 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "golang.org/x/crypto/bcrypt" +) + +const ( + nocoURL = "https://nocodb.shaiheprjct.ru/api/v2/tables/mqvqd88xe01rxap/records" + apiToken = "eVqxLwbUQRLQHQ3g44js9vfLHvIdWhllLZwKfW25" +) +// Простая структура пользователя +type User struct { + Username string `json:"username"` + Password string `json:"password"` +} + +func main() { + http.HandleFunc("/", homePage) + http.HandleFunc("/register", registerHandler) + http.HandleFunc("/login", loginHandler) + + fmt.Println("Сервер запущен на http://localhost:8080") + http.ListenAndServe(":8080", nil) +} + +// Хэширование пароля +func hashPassword(password string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14) + return string(bytes), err +} + +// Регистрация (отправка в NocoDB) +func registerHandler(w http.ResponseWriter, r *http.Request) { + if r.Method == "POST" { + user := r.FormValue("username") + pass, _ := hashPassword(r.FormValue("password")) + + jsonData, _ := json.Marshal(map[string]string{ + "username": user, + "password": pass, + }) + + req, _ := http.NewRequest("POST", nocoURL, bytes.NewBuffer(jsonData)) + req.Header.Set("xc-token", apiToken) + req.Header.Set("Content-Type", "application/json") + + client := &http.Client{} + resp, _ := client.Do(req) + defer resp.Body.Close() + + if resp.StatusCode == 200 || resp.StatusCode == 201 { + fmt.Fprint(w, "Регистрация успешна! Теперь можно войти.") + } else { + fmt.Fprint(w, "Ошибка регистрации. Возможно, имя занято.") + } + } +} + +// Вход (проверка через NocoDB) +func loginHandler(w http.ResponseWriter, r *http.Request) { + if r.Method == "POST" { + user := r.FormValue("username") + pass := r.FormValue("password") + + // Поиск пользователя в NocoDB по username + searchURL := fmt.Sprintf("%s?where=(username,eq,%s)", nocoURL, user) + req, _ := http.NewRequest("GET", searchURL, nil) + req.Header.Set("xc-token", apiToken) + + client := &http.Client{} + resp, _ := client.Do(req) + defer resp.Body.Close() + + body, _ := io.ReadAll(resp.Body) + var result struct { + List []User `json:"list"` + } + json.Unmarshal(body, &result) + + if len(result.List) > 0 { + err := bcrypt.CompareHashAndPassword([]byte(result.List[0].Password), []byte(pass)) + if err == nil { + fmt.Fprintf(w, "Добро пожаловать в личный кабинет, %s!", user) + return + } + } + fmt.Fprint(w, "Неверный логин или пароль.") + } +} + + +func homePage(w http.ResponseWriter, r *http.Request) { + // Эта строка заставит браузер отобразить форму, а не текст кода + w.Header().Set("Content-Type", "text/html; charset=utf-8") + + fmt.Fprint(w, ` + + + Личный кабинет + +

Регистрация

+
+ + + +
+
+

Вход

+
+ + + +
+ + + `) +}