| @ -0,0 +1,140 @@ | |||
| package Auth_test | |||
| import ( | |||
| "bytes" | |||
| "encoding/base64" | |||
| "encoding/json" | |||
| "io/ioutil" | |||
| "log" | |||
| "net/http" | |||
| "net/http/httptest" | |||
| "testing" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Api" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Api/Auth" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database/Seeder" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" | |||
| "github.com/gorilla/mux" | |||
| ) | |||
| func Test_Login(t *testing.T) { | |||
| log.SetOutput(ioutil.Discard) | |||
| Database.InitTest() | |||
| r := mux.NewRouter() | |||
| Api.InitAPIEndpoints(r) | |||
| ts := httptest.NewServer(r) | |||
| defer ts.Close() | |||
| userKey, _ := Seeder.GenerateAesKey() | |||
| pubKey := Seeder.GetPubKey() | |||
| p, _ := Auth.HashPassword("password") | |||
| u := Models.User{ | |||
| Username: "test", | |||
| Password: p, | |||
| AsymmetricPublicKey: Seeder.PublicKey, | |||
| AsymmetricPrivateKey: Seeder.EncryptedPrivateKey, | |||
| SymmetricKey: base64.StdEncoding.EncodeToString( | |||
| Seeder.EncryptWithPublicKey(userKey.Key, pubKey), | |||
| ), | |||
| } | |||
| err := Database.CreateUser(&u) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| d := struct { | |||
| Username string `json:"username"` | |||
| Password string `json:"password"` | |||
| }{ | |||
| Username: "test", | |||
| Password: "password", | |||
| } | |||
| jsonStr, _ := json.Marshal(d) | |||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/login", bytes.NewBuffer(jsonStr)) | |||
| req.Header.Set("Content-Type", "application/json") | |||
| client := &http.Client{} | |||
| resp, err := client.Do(req) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| if resp.StatusCode != http.StatusOK { | |||
| t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode) | |||
| return | |||
| } | |||
| var session Models.Session | |||
| err = Database.DB.First(&session, "user_id = ?", u.ID.String()).Error | |||
| if err != nil { | |||
| t.Errorf("Expected user record, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| } | |||
| func Test_Login_PasswordFails(t *testing.T) { | |||
| log.SetOutput(ioutil.Discard) | |||
| Database.InitTest() | |||
| r := mux.NewRouter() | |||
| Api.InitAPIEndpoints(r) | |||
| ts := httptest.NewServer(r) | |||
| defer ts.Close() | |||
| userKey, _ := Seeder.GenerateAesKey() | |||
| pubKey := Seeder.GetPubKey() | |||
| p, _ := Auth.HashPassword("password") | |||
| u := Models.User{ | |||
| Username: "test", | |||
| Password: p, | |||
| AsymmetricPublicKey: Seeder.PublicKey, | |||
| AsymmetricPrivateKey: Seeder.EncryptedPrivateKey, | |||
| SymmetricKey: base64.StdEncoding.EncodeToString( | |||
| Seeder.EncryptWithPublicKey(userKey.Key, pubKey), | |||
| ), | |||
| } | |||
| err := Database.CreateUser(&u) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| d := struct { | |||
| Username string `json:"username"` | |||
| Password string `json:"password"` | |||
| }{ | |||
| Username: "test", | |||
| Password: "password1", | |||
| } | |||
| jsonStr, _ := json.Marshal(d) | |||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/login", bytes.NewBuffer(jsonStr)) | |||
| req.Header.Set("Content-Type", "application/json") | |||
| client := &http.Client{} | |||
| resp, err := client.Do(req) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| if resp.StatusCode != http.StatusUnauthorized { | |||
| t.Errorf("Expected %d, recieved %d", http.StatusUnauthorized, resp.StatusCode) | |||
| return | |||
| } | |||
| } | |||
| @ -0,0 +1,131 @@ | |||
| package Auth_test | |||
| import ( | |||
| "bytes" | |||
| "encoding/base64" | |||
| "encoding/json" | |||
| "io/ioutil" | |||
| "log" | |||
| "net/http" | |||
| "net/http/cookiejar" | |||
| "net/http/httptest" | |||
| "net/url" | |||
| "sync" | |||
| "testing" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Api" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Api/Auth" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database/Seeder" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" | |||
| "github.com/gorilla/mux" | |||
| ) | |||
| type Jar struct { | |||
| lk sync.Mutex | |||
| cookies map[string][]*http.Cookie | |||
| } | |||
| func Test_Logout(t *testing.T) { | |||
| log.SetOutput(ioutil.Discard) | |||
| Database.InitTest() | |||
| r := mux.NewRouter() | |||
| Api.InitAPIEndpoints(r) | |||
| ts := httptest.NewServer(r) | |||
| defer ts.Close() | |||
| userKey, _ := Seeder.GenerateAesKey() | |||
| pubKey := Seeder.GetPubKey() | |||
| p, _ := Auth.HashPassword("password") | |||
| u := Models.User{ | |||
| Username: "test", | |||
| Password: p, | |||
| AsymmetricPublicKey: Seeder.PublicKey, | |||
| AsymmetricPrivateKey: Seeder.EncryptedPrivateKey, | |||
| SymmetricKey: base64.StdEncoding.EncodeToString( | |||
| Seeder.EncryptWithPublicKey(userKey.Key, pubKey), | |||
| ), | |||
| } | |||
| err := Database.CreateUser(&u) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| d := struct { | |||
| Username string `json:"username"` | |||
| Password string `json:"password"` | |||
| }{ | |||
| Username: "test", | |||
| Password: "password", | |||
| } | |||
| jsonStr, _ := json.Marshal(d) | |||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/login", bytes.NewBuffer(jsonStr)) | |||
| req.Header.Set("Content-Type", "application/json") | |||
| client := &http.Client{} | |||
| resp, err := client.Do(req) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| if resp.StatusCode != http.StatusOK { | |||
| t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode) | |||
| return | |||
| } | |||
| var session Models.Session | |||
| err = Database.DB.First(&session, "user_id = ?", u.ID.String()).Error | |||
| if err != nil { | |||
| t.Errorf("Expected session record, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| jar, err := cookiejar.New(nil) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| } | |||
| url, _ := url.Parse(ts.URL) | |||
| jar.SetCookies( | |||
| url, | |||
| []*http.Cookie{ | |||
| &http.Cookie{ | |||
| Name: "session_token", | |||
| Value: session.ID.String(), | |||
| MaxAge: 300, | |||
| }, | |||
| }, | |||
| ) | |||
| client = &http.Client{ | |||
| Jar: jar, | |||
| } | |||
| resp, err = client.Get(ts.URL + "/api/v1/logout") | |||
| if err != nil { | |||
| t.Errorf("Expected user record, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| if resp.StatusCode != http.StatusOK { | |||
| t.Errorf("Expected %d, recieved %d", http.StatusOK, resp.StatusCode) | |||
| return | |||
| } | |||
| err = Database.DB.First(&session, "user_id = ?", u.ID.String()).Error | |||
| if err == nil { | |||
| t.Errorf("Expected no session record, recieved %s", session.UserID) | |||
| return | |||
| } | |||
| } | |||
| @ -0,0 +1,168 @@ | |||
| package Auth_test | |||
| import ( | |||
| "bytes" | |||
| "encoding/base64" | |||
| "encoding/json" | |||
| "io/ioutil" | |||
| "log" | |||
| "net/http" | |||
| "net/http/httptest" | |||
| "testing" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Api" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Database/Seeder" | |||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" | |||
| "github.com/gorilla/mux" | |||
| ) | |||
| func Test_Signup(t *testing.T) { | |||
| log.SetOutput(ioutil.Discard) | |||
| Database.InitTest() | |||
| r := mux.NewRouter() | |||
| Api.InitAPIEndpoints(r) | |||
| ts := httptest.NewServer(r) | |||
| defer ts.Close() | |||
| userKey, _ := Seeder.GenerateAesKey() | |||
| pubKey := Seeder.GetPubKey() | |||
| d := struct { | |||
| Username string `json:"username"` | |||
| Password string `json:"password"` | |||
| ConfirmPassword string `json:"confirm_password"` | |||
| PubKey string `json:"asymmetric_public_key"` | |||
| PrivKey string `json:"asymmetric_private_key"` | |||
| SymKey string `json:"symmetric_key"` | |||
| }{ | |||
| Username: "test", | |||
| Password: "password", | |||
| ConfirmPassword: "password", | |||
| PubKey: Seeder.PublicKey, | |||
| PrivKey: Seeder.EncryptedPrivateKey, | |||
| SymKey: base64.StdEncoding.EncodeToString( | |||
| Seeder.EncryptWithPublicKey(userKey.Key, pubKey), | |||
| ), | |||
| } | |||
| jsonStr, _ := json.Marshal(d) | |||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/signup", bytes.NewBuffer(jsonStr)) | |||
| req.Header.Set("Content-Type", "application/json") | |||
| client := &http.Client{} | |||
| resp, err := client.Do(req) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| if resp.StatusCode != http.StatusNoContent { | |||
| t.Errorf("Expected %d, recieved %d", http.StatusNoContent, resp.StatusCode) | |||
| return | |||
| } | |||
| var user Models.User | |||
| err = Database.DB.First(&user, "username = ?", "test").Error | |||
| if err != nil { | |||
| t.Errorf("Expected user record, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| } | |||
| func Test_Signup_PasswordMismatchFails(t *testing.T) { | |||
| log.SetOutput(ioutil.Discard) | |||
| Database.InitTest() | |||
| r := mux.NewRouter() | |||
| Api.InitAPIEndpoints(r) | |||
| ts := httptest.NewServer(r) | |||
| defer ts.Close() | |||
| userKey, _ := Seeder.GenerateAesKey() | |||
| pubKey := Seeder.GetPubKey() | |||
| d := struct { | |||
| Username string `json:"username"` | |||
| Password string `json:"password"` | |||
| ConfirmPassword string `json:"confirm_password"` | |||
| PubKey string `json:"asymmetric_public_key"` | |||
| PrivKey string `json:"asymmetric_private_key"` | |||
| SymKey string `json:"symmetric_key"` | |||
| }{ | |||
| Username: "test", | |||
| Password: "password", | |||
| ConfirmPassword: "password1", | |||
| PubKey: Seeder.PublicKey, | |||
| PrivKey: Seeder.EncryptedPrivateKey, | |||
| SymKey: base64.StdEncoding.EncodeToString( | |||
| Seeder.EncryptWithPublicKey(userKey.Key, pubKey), | |||
| ), | |||
| } | |||
| jsonStr, _ := json.Marshal(d) | |||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/signup", bytes.NewBuffer(jsonStr)) | |||
| req.Header.Set("X-Custom-Header", "myvalue") | |||
| req.Header.Set("Content-Type", "application/json") | |||
| client := &http.Client{} | |||
| resp, err := client.Do(req) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| return | |||
| } | |||
| if resp.StatusCode != http.StatusUnprocessableEntity { | |||
| t.Errorf("Expected %d, recieved %d", http.StatusUnprocessableEntity, resp.StatusCode) | |||
| return | |||
| } | |||
| } | |||
| func Test_Signup_MissingDataFails(t *testing.T) { | |||
| log.SetOutput(ioutil.Discard) | |||
| Database.InitTest() | |||
| r := mux.NewRouter() | |||
| Api.InitAPIEndpoints(r) | |||
| ts := httptest.NewServer(r) | |||
| defer ts.Close() | |||
| d := struct { | |||
| Username string `json:"username"` | |||
| Password string `json:"password"` | |||
| ConfirmPassword string `json:"confirm_password"` | |||
| PubKey string `json:"asymmetric_public_key"` | |||
| PrivKey string `json:"asymmetric_private_key"` | |||
| SymKey string `json:"symmetric_key"` | |||
| }{ | |||
| Username: "test", | |||
| Password: "password", | |||
| ConfirmPassword: "password", | |||
| PubKey: "", | |||
| PrivKey: "", | |||
| SymKey: "", | |||
| } | |||
| jsonStr, _ := json.Marshal(d) | |||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/signup", bytes.NewBuffer(jsonStr)) | |||
| req.Header.Set("X-Custom-Header", "myvalue") | |||
| req.Header.Set("Content-Type", "application/json") | |||
| client := &http.Client{} | |||
| resp, err := client.Do(req) | |||
| if err != nil { | |||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||
| } | |||
| if resp.StatusCode != http.StatusUnprocessableEntity { | |||
| t.Errorf("Expected %d, recieved %d", http.StatusUnprocessableEntity, resp.StatusCode) | |||
| } | |||
| } | |||
| @ -0,0 +1,16 @@ | |||
| FROM golang:1.19-alpine | |||
| RUN mkdir -p /go/src/git.tovijaeschke.xyz/Capsule/Backend | |||
| COPY ./ /go/src/git.tovijaeschke.xyz/Capsule/Backend | |||
| WORKDIR /go/src/git.tovijaeschke.xyz/Capsule/Backend | |||
| # For "go test" | |||
| RUN apk add gcc libc-dev | |||
| RUN go mod download | |||
| RUN go build -o /go/bin/capsule-server main.go | |||
| CMD [ "/go/bin/capsule-server" ] | |||
| @ -0,0 +1,49 @@ | |||
| version: "3" | |||
| services: | |||
| server: | |||
| build: | |||
| context: ./Backend | |||
| ports: | |||
| - "8080:8080" | |||
| volumes: | |||
| - "./Backend:/app" | |||
| links: | |||
| - postgres | |||
| - postgres-testing | |||
| depends_on: | |||
| postgres: | |||
| condition: service_healthy | |||
| depends_on: | |||
| postgres-testing: | |||
| condition: service_healthy | |||
| postgres: | |||
| image: postgres:14.5 | |||
| ports: | |||
| - "54321:5432" | |||
| environment: | |||
| POSTGRES_DB: capsule | |||
| POSTGRES_PASSWORD: password | |||
| volumes: | |||
| - /var/lib/postgres | |||
| healthcheck: | |||
| test: ["CMD-SHELL", "pg_isready -U postgres"] | |||
| interval: 5s | |||
| timeout: 5s | |||
| retries: 5 | |||
| postgres-testing: | |||
| image: postgres:14.5 | |||
| ports: | |||
| - "54322:5432" | |||
| environment: | |||
| POSTGRES_DB: capsule-testing | |||
| POSTGRES_PASSWORD: password | |||
| tmpfs: | |||
| - /var/lib/mysql | |||
| healthcheck: | |||
| test: ["CMD-SHELL", "pg_isready -U postgres"] | |||
| interval: 5s | |||
| timeout: 5s | |||
| retries: 5 | |||
| @ -0,0 +1,3 @@ | |||
| #!/bin/sh | |||
| docker-compose exec server sh -c "cd /app && go test -v ./Api/Auth" | |||