Initial commit
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,41 @@
|
||||
CREATE USER `gemasnotesuser`@`%` IDENTIFIED WITH mysql_native_password BY 'hAP[Vl1~4<?7@Sf1Xd';
|
||||
|
||||
USE `gemasnotes`;
|
||||
|
||||
DROP TABLE IF EXISTS `User`;
|
||||
CREATE TABLE `User` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`email` varchar(150) DEFAULT NULL,
|
||||
`username` varchar(50) DEFAULT NULL,
|
||||
`password` varchar(32) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
INSERT INTO User(email,username,password) VALUES ('checker@gemasnotes.id','checker','a6005967f8e6e0ee346804765900f41f');
|
||||
|
||||
DROP TABLE IF EXISTS `Notes`;
|
||||
CREATE TABLE `Notes` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`title` varchar(100) DEFAULT NULL,
|
||||
`content` longtext,
|
||||
`author` int(11) DEFAULT NULL,
|
||||
`date` varchar(20) DEFAULT NULL,
|
||||
`tags` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `fk_user` (`author`),
|
||||
CONSTRAINT `fk_user` FOREIGN KEY (`author`) REFERENCES `User` (`id`)
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS `rewards`;
|
||||
CREATE TABLE `rewards` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`fl4gg` varchar(60),
|
||||
PRIMARY KEY (`id`)
|
||||
);
|
||||
|
||||
INSERT INTO rewards(fl4gg) VALUES ('WRECKIT50{e54e6f6ba0c7cbb4eb7a2016e2f17842}');
|
||||
|
||||
GRANT SELECT,INSERT,UPDATE,DELETE ON `User` TO `gemasnotesuser`@`%`;
|
||||
GRANT SELECT,INSERT,UPDATE,DELETE ON `Notes` TO `gemasnotesuser`@`%`;
|
||||
GRANT SELECT ON `rewards` TO `gemasnotesuser`@`%`;
|
||||
FLUSH PRIVILEGES;
|
||||
@@ -0,0 +1,22 @@
|
||||
FROM public.ecr.aws/docker/library/golang
|
||||
|
||||
ARG PASSWORD
|
||||
|
||||
RUN echo root:${PASSWORD} | chpasswd
|
||||
RUN apt-get update && apt-get install -y openssh-server curl
|
||||
RUN echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
|
||||
RUN echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
|
||||
RUN service ssh start
|
||||
|
||||
WORKDIR /app/src
|
||||
COPY ./src/go.mod ./
|
||||
COPY ./src/go.sum ./
|
||||
RUN go mod download
|
||||
|
||||
COPY ./src ./
|
||||
RUN rm -rf ./logs && mkdir ./logs
|
||||
RUN chmod +x /app/src/*.sh
|
||||
|
||||
EXPOSE 3000 22
|
||||
|
||||
ENTRYPOINT [ "/bin/sh", "-c", "/app/src/start.sh"]
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db": {
|
||||
"type": "mysql",
|
||||
"host": "database",
|
||||
"port": 3306,
|
||||
"username": "gemasnotesuser",
|
||||
"password": "hAP[Vl1~4<?7@Sf1Xd",
|
||||
"database": "gemasnotes"
|
||||
},
|
||||
"log": {
|
||||
"logfile" : "logs/backend.log",
|
||||
"format": "json",
|
||||
"timestampformat": "2006-01-02T15:04:05.000"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package notescontrollers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
models "note-service/models/notes"
|
||||
. "note-service/utils/helper"
|
||||
session "note-service/utils/session"
|
||||
"strconv"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type BaseHandler struct {
|
||||
noteRepo models.NotesRepository
|
||||
log *logrus.Logger
|
||||
}
|
||||
|
||||
func NewBaseHandler(noteRepo models.NotesRepository, log *logrus.Logger) *BaseHandler {
|
||||
return &BaseHandler{
|
||||
noteRepo: noteRepo,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *BaseHandler) GetNotes(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
var notes *[]models.Notes
|
||||
var err error
|
||||
if r.Method == "GET" {
|
||||
notes, err = h.noteRepo.GetNotes()
|
||||
} else if r.Method == "POST" && r.Header.Get("Content-Type") == "application/json" {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
title, err := jsonparser.GetString([]byte(body), "title")
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
notes, err = h.noteRepo.GetNotesByTitle(title)
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
SendJSONResp(w, notes)
|
||||
}
|
||||
|
||||
func (h *BaseHandler) GetDetailNotes(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
notes, err := h.noteRepo.GetDetailNotes(ps.ByName("id"))
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
SendJSONResp(w, notes)
|
||||
}
|
||||
|
||||
func (h *BaseHandler) DeleteNote(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
claims, respCode := session.GetData(r)
|
||||
if respCode != 200 {
|
||||
w.WriteHeader(respCode)
|
||||
return
|
||||
}
|
||||
result := h.noteRepo.DeleteNote(ps.ByName("id"), claims.Id)
|
||||
if result {
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func (h *BaseHandler) GetNotesCount(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
var raw map[string]int
|
||||
var countResp string
|
||||
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
key, err := jsonparser.GetString([]byte(body), "count_by")
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if key != "title" && key != "tags" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
keyword, err := jsonparser.GetString([]byte(body), "keyword")
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
count, err := h.noteRepo.GetNotesCount(key, keyword)
|
||||
if err != nil {
|
||||
countResp = `{"count":0}`
|
||||
} else {
|
||||
countResp = fmt.Sprintf(`{"count":%d}`, *count)
|
||||
}
|
||||
_ = json.Unmarshal([]byte(countResp), &raw)
|
||||
SendJSONResp(w, raw)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *BaseHandler) InsertUpdateNote(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
claims, respCode := session.GetData(r)
|
||||
if respCode != 200 {
|
||||
w.WriteHeader(respCode)
|
||||
return
|
||||
}
|
||||
|
||||
resp := map[string]int{"PUT": 201, "PATCH": 204}
|
||||
method := r.Method
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
noteDetail := models.Notes{}
|
||||
err := decoder.Decode(¬eDetail)
|
||||
if err != nil {
|
||||
h.log.Errorln(err)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
noteDetail.Author = strconv.Itoa(claims.Id)
|
||||
var result bool
|
||||
if method == "PUT" {
|
||||
result = h.noteRepo.InsertUpdateNote(noteDetail, 1)
|
||||
} else if method == "PATCH" {
|
||||
result = h.noteRepo.InsertUpdateNote(noteDetail, 2)
|
||||
}
|
||||
if result {
|
||||
w.WriteHeader(resp[method])
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
} else {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package usercontrollers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
models "note-service/models/user"
|
||||
. "note-service/utils/helper"
|
||||
session "note-service/utils/session"
|
||||
"reflect"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type BaseHandler struct {
|
||||
userRepo models.UserRepository
|
||||
log *logrus.Logger
|
||||
}
|
||||
|
||||
func NewBaseHandler(userRepo models.UserRepository, log *logrus.Logger) *BaseHandler {
|
||||
return &BaseHandler{
|
||||
userRepo: userRepo,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *BaseHandler) GetProfile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
var user *models.User
|
||||
var err error
|
||||
|
||||
claims, resp_code := session.GetData(r)
|
||||
if resp_code != 200 {
|
||||
w.WriteHeader(resp_code)
|
||||
return
|
||||
}
|
||||
|
||||
user, err = h.userRepo.GetProfile(claims.Id)
|
||||
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
}
|
||||
SendJSONResp(w, user)
|
||||
}
|
||||
|
||||
func (h *BaseHandler) Logout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
claims, resp_code := session.GetData(r)
|
||||
if resp_code != 200 {
|
||||
w.WriteHeader(resp_code)
|
||||
return
|
||||
}
|
||||
session.RemoveToken(claims.Id)
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "token",
|
||||
Value: "",
|
||||
MaxAge: -1,
|
||||
})
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func (h *BaseHandler) LoginCheck(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
var raw map[string]interface{}
|
||||
var resp string
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
userModel := models.User{}
|
||||
err := decoder.Decode(&userModel)
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
userData, err := h.userRepo.LoginCheck(userModel.Email, userModel.Password)
|
||||
|
||||
if err != nil || reflect.DeepEqual(userData, (models.User{})) {
|
||||
resp = `{"success":false,"message":"User Not Found"}`
|
||||
} else {
|
||||
token, exp, err := session.GenerateToken(userData.Id, userData.Username)
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
resp = `{"success":false,"message":"User Not Found"}`
|
||||
} else {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: "token",
|
||||
Value: token,
|
||||
Expires: exp,
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
})
|
||||
resp = fmt.Sprintf(`{"success":true,"message":"Access Granted","token":"%s"}`, token)
|
||||
}
|
||||
}
|
||||
_ = json.Unmarshal([]byte(resp), &raw)
|
||||
SendJSONResp(w, raw)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *BaseHandler) AddUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
if r.Header.Get("Content-Type") == "application/json" {
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
userModel := models.User{}
|
||||
err := decoder.Decode(&userModel)
|
||||
if err != nil {
|
||||
h.log.Errorln(err.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
result := h.userRepo.AddUser(userModel)
|
||||
if result {
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
module note-service
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/buger/jsonparser v1.1.1
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/jmoiron/sqlx v1.3.1
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/rs/cors v1.7.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
)
|
||||
@@ -0,0 +1,26 @@
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE=
|
||||
github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -0,0 +1,50 @@
|
||||
{"level":"info","msg":"[ ] POST /api/register insomnia/2023.3.0","time":"2023-09-07T03:21:34.032"}
|
||||
{"level":"info","msg":"[ ] POST /api/register insomnia/2023.3.0","time":"2023-09-07T03:23:53.730"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:24:18.329"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:25:14.577"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:26:51.703"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:29:46.715"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:33:38.244"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:38:06.990"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:38:14.326"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:38:30.889"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:39:08.407"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:39:19.161"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:41:13.969"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:41:18.505"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:43:46.721"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:43:50.920"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:45:21.305"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:45:22.683"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:45:23.331"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:46:06.583"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:46:19.184"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:52:47.220"}
|
||||
{"level":"error","msg":"Key path not found","time":"2023-09-07T03:52:47.221"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:53:05.212"}
|
||||
{"level":"error","msg":"json: cannot unmarshal string into Go value of type usermodels.User","time":"2023-09-07T03:53:05.213"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:55:19.037"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:55:26.126"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:56:19.436"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:57:22.835"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T03:58:13.509"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:58:30.111"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:59:00.225"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:59:14.632"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:59:20.361"}
|
||||
{"level":"error","msg":"Error 1054: Unknown column 'a' in 'field list'","time":"2023-09-07T03:59:20.368"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:59:24.919"}
|
||||
{"level":"error","msg":"Error 1054: Unknown column 'b' in 'field list'","time":"2023-09-07T03:59:24.920"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T03:59:40.476"}
|
||||
{"level":"error","msg":"sql: Scan error on column index 0, name \"count(*)\": converting driver.Value type []uint8 (\"a\") to a int: invalid syntax","time":"2023-09-07T03:59:40.481"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:00:15.759"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:00:20.578"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:00:25.099"}
|
||||
{"level":"info","msg":"[ ] POST /api/login insomnia/2023.3.0","time":"2023-09-07T04:01:32.865"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:01:40.792"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:01:53.832"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:10:12.009"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:11:26.797"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:12:18.201"}
|
||||
{"level":"info","msg":"[ ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:16:54.433"}
|
||||
{"level":"info","msg":"[ 127.0.0.1 ] POST /api/notes/count insomnia/2023.3.0","time":"2023-09-07T04:17:13.273"}
|
||||
@@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
notescontrollers "note-service/controllers/notes"
|
||||
usercontrollers "note-service/controllers/user"
|
||||
notesrepo "note-service/repository/notes"
|
||||
userrepo "note-service/repository/user"
|
||||
|
||||
. "note-service/utils/db"
|
||||
. "note-service/utils/middleware"
|
||||
. "note-service/utils/session"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/rs/cors"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data, _ := ioutil.ReadFile("config/default.json")
|
||||
logfile, log := SetupLogger(data)
|
||||
db := Connect_db(data)
|
||||
|
||||
userRepo := userrepo.NewUserRepo(db, logfile)
|
||||
userHandler := usercontrollers.NewBaseHandler(userRepo, logfile)
|
||||
|
||||
noteRepo := notesrepo.NewNotesRepo(db, logfile)
|
||||
noteHandler := notescontrollers.NewBaseHandler(noteRepo, logfile)
|
||||
|
||||
c := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"https://*", "http://*"},
|
||||
AllowCredentials: true,
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "PATCH"},
|
||||
})
|
||||
|
||||
router := httprouter.New()
|
||||
router.ServeFiles("/assets/*filepath", http.Dir("./assets"))
|
||||
|
||||
handler := c.Handler(router)
|
||||
|
||||
// users routes
|
||||
router.POST("/api/register", Logger(userHandler.AddUser))
|
||||
router.POST("/api/login", Logger(userHandler.LoginCheck))
|
||||
router.GET("/api/logout", Logger(userHandler.Logout))
|
||||
router.GET("/api/profile", Logger(AuthorizationCheck(userHandler.GetProfile)))
|
||||
|
||||
// notes routes
|
||||
router.POST("/api/notes", Logger(noteHandler.GetNotes))
|
||||
router.GET("/api/notes", Logger(noteHandler.GetNotes))
|
||||
router.GET("/api/notes/:id", Logger(noteHandler.GetDetailNotes))
|
||||
router.PUT("/api/notes", Logger(AuthorizationCheck(noteHandler.InsertUpdateNote)))
|
||||
router.PATCH("/api/notes", Logger(AuthorizationCheck(noteHandler.InsertUpdateNote)))
|
||||
router.DELETE("/api/notes/:id", Logger(AuthorizationCheck(noteHandler.DeleteNote)))
|
||||
|
||||
// analytics routes
|
||||
router.POST("/api/notes/count", Logger(AuthorizationCheck(noteHandler.GetNotesCount)))
|
||||
|
||||
log.Infoln("Server running on port :3000")
|
||||
err := http.ListenAndServe(":3000", handler)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package notesmodels
|
||||
|
||||
type Notes struct {
|
||||
Id int `json:"id" db:"id"`
|
||||
Title string `json:"title" db:"title"`
|
||||
Author string `json:"author" db:"author"`
|
||||
Date string `json:"date" db:"date"`
|
||||
Content string `json:"content,omitempty" db:"content"`
|
||||
Tags string `json:"tags" db:"tags"`
|
||||
}
|
||||
|
||||
type NotesRepository interface {
|
||||
GetNotes() (*[]Notes, error)
|
||||
GetNotesByTitle(title string) (*[]Notes, error)
|
||||
InsertUpdateNote(note Notes, op int) bool
|
||||
GetNotesCount(key string, keyword string) (*int, error)
|
||||
DeleteNote(id string, author int) bool
|
||||
GetDetailNotes(id string) (*Notes, error)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package usermodels
|
||||
|
||||
type User struct {
|
||||
Id int `json:"id" db:"id"`
|
||||
Username string `json:"username" db:"username"`
|
||||
Password string `json:"password,omitempty" db:"password"`
|
||||
Email string `json:"email" db:"email"`
|
||||
}
|
||||
|
||||
type UserRepository interface {
|
||||
LoginCheck(Username string, Password string) (*User, error)
|
||||
GetProfile(id int) (*User, error)
|
||||
AddUser(user User) bool
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package notesrepo
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
models "note-service/models/notes"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const simpleNote = "SELECT Notes.id, title, User.email as author, date FROM Notes, User WHERE Notes.author=User.id ORDER BY Notes.id DESC"
|
||||
const simpleNoteFilter = "SELECT Notes.id, title, User.email as author, date FROM Notes, User WHERE Notes.author=User.id AND Notes.title LIKE ?"
|
||||
const detailNote = "SELECT Notes.id as id, title, User.email as author, date, content, tags FROM Notes, User WHERE Notes.author=User.id AND Notes.id=?"
|
||||
const insertNote = "INSERT INTO Notes(title,content,author,date,tags) VALUES (?,?,?,DATE_FORMAT(NOW(), '%M %d, %Y'),?)"
|
||||
const countNote = "SELECT count(*) FROM Notes WHERE %s LIKE '%%%s%%'"
|
||||
const updateNote = "UPDATE Notes SET title = ?, content = ?, date = DATE_FORMAT(NOW(), '%M %d, %Y') WHERE author = ? AND id = ?"
|
||||
const deleteNote = "DELETE FROM Notes WHERE id = ? AND author = ?"
|
||||
|
||||
type NotesRepo struct {
|
||||
db *sqlx.DB
|
||||
log *logrus.Logger
|
||||
}
|
||||
|
||||
func NewNotesRepo(db *sqlx.DB, log *logrus.Logger) *NotesRepo {
|
||||
return &NotesRepo{db: db, log: log}
|
||||
}
|
||||
|
||||
func (r *NotesRepo) GetDetailNotes(id string) (*models.Notes, error) {
|
||||
data := models.Notes{}
|
||||
stmt, err := r.db.Preparex(detailNote)
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
}
|
||||
defer stmt.Close()
|
||||
err = stmt.QueryRowx(id).StructScan(&data)
|
||||
if err != nil {
|
||||
r.log.Errorln(err)
|
||||
}
|
||||
return &data, err
|
||||
}
|
||||
|
||||
func (r *NotesRepo) GetNotes() (*[]models.Notes, error) {
|
||||
data := []models.Notes{}
|
||||
stmt, err := r.db.Preparex(simpleNote)
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
}
|
||||
defer stmt.Close()
|
||||
err = stmt.Select(&data)
|
||||
if err != nil {
|
||||
return &data, err
|
||||
}
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (r *NotesRepo) GetNotesByTitle(title string) (*[]models.Notes, error) {
|
||||
data := []models.Notes{}
|
||||
err := r.db.Select(&data, simpleNoteFilter, title)
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
}
|
||||
return &data, err
|
||||
}
|
||||
|
||||
func (r *NotesRepo) GetNotesCount(key string, keyword string) (*int, error) {
|
||||
var count int
|
||||
err := r.db.Get(&count, fmt.Sprintf(countNote, key, keyword))
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
}
|
||||
return &count, err
|
||||
}
|
||||
|
||||
func (r *NotesRepo) InsertUpdateNote(notes models.Notes, op int) bool {
|
||||
var result sql.Result
|
||||
if op == 1 {
|
||||
result = r.db.MustExec(insertNote, notes.Title, notes.Content, notes.Author, notes.Tags)
|
||||
} else {
|
||||
result = r.db.MustExec(updateNote, notes.Title, notes.Content, notes.Author, notes.Id)
|
||||
}
|
||||
affectedRows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
return false
|
||||
}
|
||||
if affectedRows > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *NotesRepo) DeleteNote(id string, author int) bool {
|
||||
result := r.db.MustExec(deleteNote, id, author)
|
||||
affectedRows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
return false
|
||||
}
|
||||
if affectedRows > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package userrepo
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
models "note-service/models/user"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const getProfileQuery = "SELECT id,username,email FROM User WHERE id=?"
|
||||
const loginQuery = "SELECT * FROM User WHERE email=? AND password=MD5(?)"
|
||||
const addUserQuery = "INSERT INTO User(username,password,email) VALUES (?,md5(?),?)"
|
||||
|
||||
type UserRepo struct {
|
||||
db *sqlx.DB
|
||||
log *logrus.Logger
|
||||
}
|
||||
|
||||
func NewUserRepo(db *sqlx.DB, log *logrus.Logger) *UserRepo {
|
||||
return &UserRepo{db: db, log: log}
|
||||
}
|
||||
|
||||
func affected(result sql.Result, r *UserRepo) bool {
|
||||
affectedRows, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
return false
|
||||
}
|
||||
if affectedRows > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *UserRepo) GetProfile(id int) (*models.User, error) {
|
||||
data := models.User{}
|
||||
stmt, err := r.db.Preparex(getProfileQuery)
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
}
|
||||
defer stmt.Close()
|
||||
err = stmt.QueryRowx(id).StructScan(&data)
|
||||
if err != nil {
|
||||
return &data, err
|
||||
}
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (r *UserRepo) LoginCheck(user string, pass string) (*models.User, error) {
|
||||
data := models.User{}
|
||||
stmt, err := r.db.Preparex(loginQuery)
|
||||
if err != nil {
|
||||
r.log.Errorln(err.Error())
|
||||
}
|
||||
defer stmt.Close()
|
||||
err = stmt.QueryRowx(user, pass).StructScan(&data)
|
||||
if err != nil {
|
||||
return &data, err
|
||||
}
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
func (r *UserRepo) AddUser(user models.User) bool {
|
||||
result := r.db.MustExec(addUserQuery, user.Username, user.Password, user.Email)
|
||||
return affected(result, r)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o gw.app .
|
||||
/app/src/gw.app
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
/usr/sbin/sshd -D &
|
||||
|
||||
cd /app/src/ && ./run.sh
|
||||
@@ -0,0 +1,41 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type DBConfig struct {
|
||||
Db DBData `json:"db"`
|
||||
}
|
||||
|
||||
type DBData struct {
|
||||
DBType string `json:"type"`
|
||||
DBHost string `json:"host"`
|
||||
DBPort int `json:"port"`
|
||||
User string `json:"username"`
|
||||
Pass string `json:"password"`
|
||||
DBName string `json:"database"`
|
||||
}
|
||||
|
||||
func Connect_db(config []byte) *sqlx.DB {
|
||||
data := DBConfig{}
|
||||
_ = json.Unmarshal([]byte(config), &data)
|
||||
connection_string := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", data.Db.User, data.Db.Pass, data.Db.DBHost, data.Db.DBPort, data.Db.DBName)
|
||||
|
||||
db, err := sqlx.Open(data.Db.DBType, connection_string)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
return db
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func SendJSONResp(w http.ResponseWriter, data interface{}) {
|
||||
resp, _ := json.Marshal(data)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(resp)
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type LogData struct {
|
||||
Logfile string `json:"logfile"`
|
||||
TimestampFormat string `json:"timestampformat"`
|
||||
Format string `json:"format"`
|
||||
}
|
||||
|
||||
type LogConfig struct {
|
||||
Log LogData `json:"log"`
|
||||
}
|
||||
|
||||
var Logging *logrus.Logger
|
||||
var StdoutLog *logrus.Logger
|
||||
|
||||
func setupStdOutLog(config *LogConfig) {
|
||||
StdoutLog = logrus.New()
|
||||
StdoutLog.SetFormatter(&logrus.TextFormatter{
|
||||
TimestampFormat: config.Log.TimestampFormat,
|
||||
FullTimestamp: true,
|
||||
})
|
||||
}
|
||||
|
||||
func setupLogFile(config *LogConfig) {
|
||||
Logging = logrus.New()
|
||||
|
||||
if config.Log.Format == "json" {
|
||||
Logging.SetFormatter(&logrus.JSONFormatter{
|
||||
TimestampFormat: config.Log.TimestampFormat,
|
||||
})
|
||||
} else {
|
||||
Logging.SetFormatter(&logrus.TextFormatter{
|
||||
TimestampFormat: config.Log.TimestampFormat,
|
||||
})
|
||||
}
|
||||
f, err := os.OpenFile(config.Log.Logfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
Logging.Fatal("Cannot Open Logging Files")
|
||||
}
|
||||
Logging.SetOutput(f)
|
||||
}
|
||||
|
||||
func SetupLogger(data []byte) (*logrus.Logger, *logrus.Logger) {
|
||||
config := LogConfig{}
|
||||
_ = json.Unmarshal([]byte(data), &config)
|
||||
setupStdOutLog(&config)
|
||||
setupLogFile(&config)
|
||||
return Logging, StdoutLog
|
||||
}
|
||||
|
||||
func Logger(next httprouter.Handle) httprouter.Handle {
|
||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
Logging.Infof("[ %s ] %s %s %s", r.Header.Get("X-Real-IP"), r.Method, r.URL.Path, r.Header.Get("User-Agent"))
|
||||
StdoutLog.Infof("[ %s ] %s %s %s", r.Header.Get("X-Real-IP"), r.Method, r.URL.Path, r.Header.Get("User-Agent"))
|
||||
next(w, r, ps)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
var secretKey = make([]byte, 42)
|
||||
var validSession = make(map[int]bool)
|
||||
|
||||
const tokenExpired = 10
|
||||
|
||||
type Claims struct {
|
||||
Id int
|
||||
Username string
|
||||
jwt.StandardClaims
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
rand.Read(secretKey)
|
||||
}
|
||||
|
||||
func getToken(r *http.Request) string {
|
||||
token := r.Header.Get("Authorization")
|
||||
tokenString := strings.TrimPrefix(token, "Bearer ")
|
||||
return tokenString
|
||||
}
|
||||
|
||||
func GenerateToken(id int, username string) (string, time.Time, error) {
|
||||
expirationTime := time.Now().Add(tokenExpired * time.Minute)
|
||||
claims := &Claims{
|
||||
Username: username,
|
||||
Id: id,
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
ExpiresAt: expirationTime.Unix(),
|
||||
},
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
tokenString, err := token.SignedString(secretKey)
|
||||
if err == nil {
|
||||
validSession[id] = true
|
||||
}
|
||||
return tokenString, expirationTime, err
|
||||
}
|
||||
|
||||
func GetData(r *http.Request) (*Claims, int) {
|
||||
claims := &Claims{}
|
||||
tokenStr := getToken(r)
|
||||
if tokenStr == "" {
|
||||
return claims, 401
|
||||
}
|
||||
|
||||
tkn, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return secretKey, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if err == jwt.ErrSignatureInvalid {
|
||||
return claims, 400
|
||||
}
|
||||
return claims, 401
|
||||
}
|
||||
|
||||
if tkn.Valid && validSession[claims.Id] {
|
||||
return claims, 200
|
||||
}
|
||||
return claims, 401
|
||||
}
|
||||
|
||||
func AuthorizationCheck(next httprouter.Handle) httprouter.Handle {
|
||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
_, statusCode := GetData(r)
|
||||
if statusCode != 200 {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
next(w, r, ps)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func RemoveToken(id int) {
|
||||
delete(validSession, id)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
FROM public.ecr.aws/docker/library/python:3.10
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./src/requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY ./src .
|
||||
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
@@ -0,0 +1,12 @@
|
||||
import MySQLdb
|
||||
|
||||
# Database configuration
|
||||
db_config = {
|
||||
'host': 'database',
|
||||
'user': 'root',
|
||||
'passwd': 'why_my_random_string_password_doesnot_working',
|
||||
'db': 'gemasnotes',
|
||||
}
|
||||
|
||||
# Create a connection to the database
|
||||
conn = MySQLdb.connect(**db_config)
|
||||
@@ -0,0 +1,88 @@
|
||||
from fastapi import Request, FastAPI, HTTPException, Depends
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
from validation import validation_schema
|
||||
from jsonschema import Draft7Validator,validate
|
||||
from jsonschema.exceptions import ValidationError
|
||||
from database import conn
|
||||
|
||||
@Draft7Validator.FORMAT_CHECKER.checks("security-validation",ValueError)
|
||||
def validate_payload(data):
|
||||
pattern = r'[!#$"\'`{}()]'
|
||||
return not re.search(pattern, data)
|
||||
|
||||
app = FastAPI()
|
||||
security = HTTPBasic()
|
||||
note_service = "http://gemas-notes:3000"
|
||||
|
||||
def validate_credentials(credentials):
|
||||
if credentials.username != "gemasflagreceiver" or credentials.password != "AuTeEbn%.Q5$pC_ge6":
|
||||
return False
|
||||
return True
|
||||
|
||||
@app.post("/flag_receiver")
|
||||
async def flag_receiver(request: Request, credentials: HTTPBasicCredentials = Depends(security)):
|
||||
validate_credentials(credentials)
|
||||
body = await request.json()
|
||||
flag = body["flag"]
|
||||
cursor = conn.cursor()
|
||||
query = "UPDATE rewards SET fl4gg=%s"
|
||||
cursor.execute(query, (flag,))
|
||||
conn.commit()
|
||||
count = cursor.rowcount
|
||||
cursor.close()
|
||||
return {"success": True} if count else {"success": False}
|
||||
|
||||
@app.api_route("/{path_name:path}", methods=["GET","DELETE"])
|
||||
def no_body_request(request: Request):
|
||||
client_host = request.client.host
|
||||
headers = {"X-Real-IP": client_host}
|
||||
if request.headers.get("authorization"):
|
||||
headers["Authorization"] = request.headers.get("authorization")
|
||||
|
||||
if request.method == "DELETE":
|
||||
status_code = requests.delete(note_service + request.url.path, headers=headers).status_code
|
||||
if status_code == 204:
|
||||
return {}
|
||||
raise HTTPException(status_code=500)
|
||||
|
||||
try:
|
||||
return requests.get(note_service + request.url.path, headers=headers).json()
|
||||
except:
|
||||
return []
|
||||
|
||||
@app.api_route("/{path_name:path}", methods=["POST", "PUT","PATCH"])
|
||||
async def with_body_request(request: Request):
|
||||
url_path = request.url.path
|
||||
body = await request.body()
|
||||
client_host = request.client.host
|
||||
|
||||
if request.headers.get("content-type") != "application/json":
|
||||
raise HTTPException(status_code=400, detail="Please specify JSON data")
|
||||
|
||||
try:
|
||||
headers = dict(request.headers)
|
||||
headers["X-Real-IP"] = client_host
|
||||
validate(json.loads(body), validation_schema.get(url_path), format_checker=Draft7Validator.FORMAT_CHECKER)
|
||||
|
||||
if request.method == "PUT":
|
||||
res = requests.put(note_service + url_path, data=body, headers=headers)
|
||||
elif request.method == "PATCH":
|
||||
res = requests.patch(note_service + url_path, data=body, headers=headers)
|
||||
else:
|
||||
res = requests.post(note_service + url_path, data=body, headers=headers)
|
||||
|
||||
|
||||
if res.status_code == 401:
|
||||
raise HTTPException(status_code=401, detail="Please Login")
|
||||
|
||||
if res.status_code == 200:
|
||||
return res.json()
|
||||
|
||||
return {}
|
||||
|
||||
except ValidationError as e:
|
||||
raise HTTPException(status_code=400, detail="Invalid JSON data")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
annotated-types==0.5.0
|
||||
anyio==3.7.1
|
||||
attrs==23.1.0
|
||||
certifi==2023.7.22
|
||||
charset-normalizer==3.2.0
|
||||
click==8.1.7
|
||||
exceptiongroup==1.1.3
|
||||
fastapi==0.103.1
|
||||
h11==0.14.0
|
||||
idna==3.4
|
||||
jsonschema==4.19.0
|
||||
jsonschema-specifications==2023.7.1
|
||||
pydantic==2.3.0
|
||||
pydantic_core==2.6.3
|
||||
referencing==0.30.2
|
||||
requests==2.31.0
|
||||
rpds-py==0.10.2
|
||||
sniffio==1.3.0
|
||||
starlette==0.27.0
|
||||
typing_extensions==4.7.1
|
||||
urllib3==2.0.4
|
||||
uvicorn==0.23.2
|
||||
mysqlclient
|
||||
@@ -0,0 +1,70 @@
|
||||
validation_schema = {
|
||||
"/api/register": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {
|
||||
"type": "string",
|
||||
"minLength": 5,
|
||||
"maxLength": 10,
|
||||
"format": "security-validation"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 10,
|
||||
"format": "security-validation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/login": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 10,
|
||||
"format": "security-validation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/notes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"format": "security-validation"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"minLength": 10,
|
||||
"format": "security-validation"
|
||||
},
|
||||
"tags": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"format": "security-validation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/notes/count": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"count_by": {
|
||||
"type": "string",
|
||||
"enum": ["title", "tags"]
|
||||
},
|
||||
"keyword": {
|
||||
"type": "string",
|
||||
"maxLength": 10,
|
||||
"format": "security-validation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user