| @ -0,0 +1,143 @@ | |||||
| package Auth_test | |||||
| import ( | |||||
| "bytes" | |||||
| "encoding/base64" | |||||
| "encoding/json" | |||||
| "io/ioutil" | |||||
| "log" | |||||
| "net/http" | |||||
| "net/http/cookiejar" | |||||
| "net/http/httptest" | |||||
| "net/url" | |||||
| "os" | |||||
| "testing" | |||||
| "time" | |||||
| "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_AddProfileImage(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 | |||||
| } | |||||
| session := Models.Session{ | |||||
| UserID: u.ID, | |||||
| Expiry: time.Now().Add(12 * time.Hour), | |||||
| } | |||||
| err = Database.CreateSession(&session) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| jar, err := cookiejar.New(nil) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| url, _ := url.Parse(ts.URL) | |||||
| jar.SetCookies( | |||||
| url, | |||||
| []*http.Cookie{ | |||||
| { | |||||
| Name: "session_token", | |||||
| Value: session.ID.String(), | |||||
| MaxAge: 300, | |||||
| }, | |||||
| }, | |||||
| ) | |||||
| key, err := Seeder.GenerateAesKey() | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| dat, err := os.ReadFile("./profile_picture_test.png") | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| encDat, err := key.AesEncrypt(dat) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| a := Models.Attachment{ | |||||
| Mimetype: "image/png", | |||||
| Extension: "png", | |||||
| Data: base64.StdEncoding.EncodeToString(encDat), | |||||
| } | |||||
| jsonStr, _ := json.Marshal(a) | |||||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/auth/image", bytes.NewBuffer(jsonStr)) | |||||
| req.Header.Set("Content-Type", "application/json") | |||||
| client := &http.Client{ | |||||
| Jar: jar, | |||||
| } | |||||
| 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 | |||||
| } | |||||
| u, err = Database.GetUserById(u.ID.String()) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| if u.AttachmentID.IsNil() { | |||||
| t.Errorf("Attachment not assigned to user") | |||||
| } | |||||
| err = os.Remove("/app/attachments/" + u.Attachment.FilePath) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,212 @@ | |||||
| package Auth_test | |||||
| import ( | |||||
| "bytes" | |||||
| "encoding/base64" | |||||
| "encoding/json" | |||||
| "io/ioutil" | |||||
| "log" | |||||
| "net/http" | |||||
| "net/http/cookiejar" | |||||
| "net/http/httptest" | |||||
| "net/url" | |||||
| "testing" | |||||
| "time" | |||||
| "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_ChangeMessageExpiry(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 | |||||
| } | |||||
| session := Models.Session{ | |||||
| UserID: u.ID, | |||||
| Expiry: time.Now().Add(12 * time.Hour), | |||||
| } | |||||
| err = Database.CreateSession(&session) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| jar, err := cookiejar.New(nil) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| url, _ := url.Parse(ts.URL) | |||||
| jar.SetCookies( | |||||
| url, | |||||
| []*http.Cookie{ | |||||
| { | |||||
| Name: "session_token", | |||||
| Value: session.ID.String(), | |||||
| MaxAge: 300, | |||||
| }, | |||||
| }, | |||||
| ) | |||||
| d := struct { | |||||
| MessageExpiry string `json:"message_expiry"` | |||||
| }{ | |||||
| MessageExpiry: "fifteen_min", | |||||
| } | |||||
| jsonStr, _ := json.Marshal(d) | |||||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/auth/message_expiry", bytes.NewBuffer(jsonStr)) | |||||
| req.Header.Set("Content-Type", "application/json") | |||||
| client := &http.Client{ | |||||
| Jar: jar, | |||||
| } | |||||
| 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) | |||||
| } | |||||
| u, err = Database.GetUserById(u.ID.String()) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| if u.MessageExpiryDefault.String() != "fifteen_min" { | |||||
| t.Errorf("Failed to verify the MessageExpiryDefault has been changed") | |||||
| } | |||||
| } | |||||
| func Test_ChangeMessageExpiryInvalidData(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 | |||||
| } | |||||
| session := Models.Session{ | |||||
| UserID: u.ID, | |||||
| Expiry: time.Now().Add(12 * time.Hour), | |||||
| } | |||||
| err = Database.CreateSession(&session) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| jar, err := cookiejar.New(nil) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| url, _ := url.Parse(ts.URL) | |||||
| jar.SetCookies( | |||||
| url, | |||||
| []*http.Cookie{ | |||||
| { | |||||
| Name: "session_token", | |||||
| Value: session.ID.String(), | |||||
| MaxAge: 300, | |||||
| }, | |||||
| }, | |||||
| ) | |||||
| d := struct { | |||||
| MessageExpiry string `json:"message_expiry"` | |||||
| }{ | |||||
| MessageExpiry: "invalid_message_expiry", | |||||
| } | |||||
| jsonStr, _ := json.Marshal(d) | |||||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/auth/message_expiry", bytes.NewBuffer(jsonStr)) | |||||
| req.Header.Set("Content-Type", "application/json") | |||||
| client := &http.Client{ | |||||
| Jar: jar, | |||||
| } | |||||
| 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) | |||||
| } | |||||
| u, err = Database.GetUserById(u.ID.String()) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| if u.MessageExpiryDefault.String() != "no_expiry" { | |||||
| t.Errorf("Failed to verify the MessageExpiryDefault has not been changed") | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,306 @@ | |||||
| package Auth_test | |||||
| import ( | |||||
| "bytes" | |||||
| "encoding/base64" | |||||
| "encoding/json" | |||||
| "io/ioutil" | |||||
| "log" | |||||
| "net/http" | |||||
| "net/http/cookiejar" | |||||
| "net/http/httptest" | |||||
| "net/url" | |||||
| "testing" | |||||
| "time" | |||||
| "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_ChangePassword(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 | |||||
| } | |||||
| session := Models.Session{ | |||||
| UserID: u.ID, | |||||
| Expiry: time.Now().Add(12 * time.Hour), | |||||
| } | |||||
| err = Database.CreateSession(&session) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| jar, err := cookiejar.New(nil) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| url, _ := url.Parse(ts.URL) | |||||
| jar.SetCookies( | |||||
| url, | |||||
| []*http.Cookie{ | |||||
| { | |||||
| Name: "session_token", | |||||
| Value: session.ID.String(), | |||||
| MaxAge: 300, | |||||
| }, | |||||
| }, | |||||
| ) | |||||
| d := struct { | |||||
| OldPassword string `json:"old_password"` | |||||
| NewPassword string `json:"new_password"` | |||||
| NewPasswordConfirm string `json:"new_password_confirm"` | |||||
| PrivateKey string `json:"private_key"` | |||||
| }{ | |||||
| OldPassword: "password", | |||||
| NewPassword: "password1", | |||||
| NewPasswordConfirm: "password1", | |||||
| PrivateKey: "", | |||||
| } | |||||
| jsonStr, _ := json.Marshal(d) | |||||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/auth/change_password", bytes.NewBuffer(jsonStr)) | |||||
| req.Header.Set("Content-Type", "application/json") | |||||
| client := &http.Client{ | |||||
| Jar: jar, | |||||
| } | |||||
| 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 | |||||
| } | |||||
| u, err = Database.GetUserById(u.ID.String()) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| if !Auth.CheckPasswordHash("password1", u.Password) { | |||||
| t.Errorf("Failed to verify the password has been changed") | |||||
| } | |||||
| } | |||||
| func Test_ChangePasswordMismatchConfirmFails(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 | |||||
| } | |||||
| session := Models.Session{ | |||||
| UserID: u.ID, | |||||
| Expiry: time.Now().Add(12 * time.Hour), | |||||
| } | |||||
| err = Database.CreateSession(&session) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| jar, err := cookiejar.New(nil) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| url, _ := url.Parse(ts.URL) | |||||
| jar.SetCookies( | |||||
| url, | |||||
| []*http.Cookie{ | |||||
| { | |||||
| Name: "session_token", | |||||
| Value: session.ID.String(), | |||||
| MaxAge: 300, | |||||
| }, | |||||
| }, | |||||
| ) | |||||
| d := struct { | |||||
| OldPassword string `json:"old_password"` | |||||
| NewPassword string `json:"new_password"` | |||||
| NewPasswordConfirm string `json:"new_password_confirm"` | |||||
| PrivateKey string `json:"private_key"` | |||||
| }{ | |||||
| OldPassword: "password", | |||||
| NewPassword: "password1", | |||||
| NewPasswordConfirm: "password2", | |||||
| PrivateKey: "", | |||||
| } | |||||
| jsonStr, _ := json.Marshal(d) | |||||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/auth/change_password", bytes.NewBuffer(jsonStr)) | |||||
| req.Header.Set("Content-Type", "application/json") | |||||
| client := &http.Client{ | |||||
| Jar: jar, | |||||
| } | |||||
| 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) | |||||
| } | |||||
| } | |||||
| func Test_ChangePasswordInvalidCurrentPasswordFails(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 | |||||
| } | |||||
| session := Models.Session{ | |||||
| UserID: u.ID, | |||||
| Expiry: time.Now().Add(12 * time.Hour), | |||||
| } | |||||
| err = Database.CreateSession(&session) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| jar, err := cookiejar.New(nil) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| url, _ := url.Parse(ts.URL) | |||||
| jar.SetCookies( | |||||
| url, | |||||
| []*http.Cookie{ | |||||
| { | |||||
| Name: "session_token", | |||||
| Value: session.ID.String(), | |||||
| MaxAge: 300, | |||||
| }, | |||||
| }, | |||||
| ) | |||||
| d := struct { | |||||
| OldPassword string `json:"old_password"` | |||||
| NewPassword string `json:"new_password"` | |||||
| NewPasswordConfirm string `json:"new_password_confirm"` | |||||
| PrivateKey string `json:"private_key"` | |||||
| }{ | |||||
| OldPassword: "password2", | |||||
| NewPassword: "password1", | |||||
| NewPasswordConfirm: "password1", | |||||
| PrivateKey: "", | |||||
| } | |||||
| jsonStr, _ := json.Marshal(d) | |||||
| req, _ := http.NewRequest("POST", ts.URL+"/api/v1/auth/change_password", bytes.NewBuffer(jsonStr)) | |||||
| req.Header.Set("Content-Type", "application/json") | |||||
| client := &http.Client{ | |||||
| Jar: jar, | |||||
| } | |||||
| resp, err := client.Do(req) | |||||
| if err != nil { | |||||
| t.Errorf("Expected nil, recieved %s", err.Error()) | |||||
| return | |||||
| } | |||||
| if resp.StatusCode != http.StatusForbidden { | |||||
| t.Errorf("Expected %d, recieved %d", http.StatusForbidden, resp.StatusCode) | |||||
| } | |||||
| } | |||||
| @ -1,76 +0,0 @@ | |||||
| package JsonSerialization | |||||
| import ( | |||||
| "encoding/json" | |||||
| "errors" | |||||
| "fmt" | |||||
| "strings" | |||||
| "git.tovijaeschke.xyz/tovi/Capsule/Backend/Models" | |||||
| schema "github.com/Kangaroux/go-map-schema" | |||||
| ) | |||||
| func DeserializeUser(data []byte, allowMissing []string, allowAllMissing bool) (Models.User, error) { | |||||
| var ( | |||||
| userData Models.User = Models.User{} | |||||
| jsonStructureTest map[string]interface{} = make(map[string]interface{}) | |||||
| jsonStructureTestResults *schema.CompareResults | |||||
| field schema.FieldMissing | |||||
| allowed string | |||||
| missingFields []string | |||||
| i int | |||||
| err error | |||||
| ) | |||||
| // Verify the JSON has the correct structure | |||||
| json.Unmarshal(data, &jsonStructureTest) | |||||
| jsonStructureTestResults, err = schema.CompareMapToStruct( | |||||
| &userData, | |||||
| jsonStructureTest, | |||||
| &schema.CompareOpts{ | |||||
| ConvertibleFunc: CanConvert, | |||||
| TypeNameFunc: schema.DetailedTypeName, | |||||
| }) | |||||
| if err != nil { | |||||
| return userData, err | |||||
| } | |||||
| if len(jsonStructureTestResults.MismatchedFields) > 0 { | |||||
| return userData, errors.New(fmt.Sprintf( | |||||
| "MismatchedFields found when deserializing data: %s", | |||||
| jsonStructureTestResults.Errors().Error(), | |||||
| )) | |||||
| } | |||||
| // Remove allowed missing fields from MissingFields | |||||
| for _, allowed = range allowMissing { | |||||
| for i, field = range jsonStructureTestResults.MissingFields { | |||||
| if allowed == field.String() { | |||||
| jsonStructureTestResults.MissingFields = append( | |||||
| jsonStructureTestResults.MissingFields[:i], | |||||
| jsonStructureTestResults.MissingFields[i+1:]..., | |||||
| ) | |||||
| } | |||||
| } | |||||
| } | |||||
| if !allowAllMissing && len(jsonStructureTestResults.MissingFields) > 0 { | |||||
| for _, field = range jsonStructureTestResults.MissingFields { | |||||
| missingFields = append(missingFields, field.String()) | |||||
| } | |||||
| return userData, errors.New(fmt.Sprintf( | |||||
| "MissingFields found when deserializing data: %s", | |||||
| strings.Join(missingFields, ", "), | |||||
| )) | |||||
| } | |||||
| // Deserialize the JSON into the struct | |||||
| err = json.Unmarshal(data, &userData) | |||||
| if err != nil { | |||||
| return userData, err | |||||
| } | |||||
| return userData, err | |||||
| } | |||||
| @ -1,109 +0,0 @@ | |||||
| package JsonSerialization | |||||
| import ( | |||||
| "math" | |||||
| "reflect" | |||||
| ) | |||||
| // isIntegerType returns whether the type is an integer and if it's unsigned. | |||||
| // See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L328 | |||||
| func isIntegerType(t reflect.Type) (bool, bool) { | |||||
| var ( | |||||
| yes bool | |||||
| unsigned bool | |||||
| ) | |||||
| switch t.Kind() { | |||||
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | |||||
| yes = true | |||||
| case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | |||||
| yes = true | |||||
| unsigned = true | |||||
| } | |||||
| return yes, unsigned | |||||
| } | |||||
| // isFloatType returns true if the type is a floating point. Note that this doesn't | |||||
| // care about the value -- unmarshaling the number "0" gives a float, not an int. | |||||
| // See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L319 | |||||
| func isFloatType(t reflect.Type) bool { | |||||
| var ( | |||||
| yes bool | |||||
| ) | |||||
| switch t.Kind() { | |||||
| case reflect.Float32, reflect.Float64: | |||||
| yes = true | |||||
| } | |||||
| return yes | |||||
| } | |||||
| // CanConvert returns whether value v is convertible to type t. | |||||
| // | |||||
| // If t is a pointer and v is not nil, it checks if v is convertible to the type that | |||||
| // t points to. | |||||
| // Modified due to not handling slices (DefaultCanConvert fails on PhotoUrls and Tags) | |||||
| // See: https://github.com/Kangaroux/go-map-schema/blob/master/schema.go#L191 | |||||
| func CanConvert(t reflect.Type, v reflect.Value) bool { | |||||
| var ( | |||||
| isPtr bool | |||||
| isStruct bool | |||||
| isArray bool | |||||
| dstType reflect.Type | |||||
| dstInt bool | |||||
| unsigned bool | |||||
| f float64 | |||||
| srcInt bool | |||||
| ) | |||||
| isPtr = t.Kind() == reflect.Ptr | |||||
| isStruct = t.Kind() == reflect.Struct | |||||
| isArray = t.Kind() == reflect.Array | |||||
| dstType = t | |||||
| // Check if v is a nil value. | |||||
| if !v.IsValid() || (v.CanAddr() && v.IsNil()) { | |||||
| return isPtr | |||||
| } | |||||
| // If the dst is a pointer, check if we can convert to the type it's pointing to. | |||||
| if isPtr { | |||||
| dstType = t.Elem() | |||||
| isStruct = t.Elem().Kind() == reflect.Struct | |||||
| } | |||||
| // If the dst is a struct, we should check its nested fields. | |||||
| if isStruct { | |||||
| return v.Kind() == reflect.Map | |||||
| } | |||||
| if isArray { | |||||
| return v.Kind() == reflect.String | |||||
| } | |||||
| if t.Kind() == reflect.Slice { | |||||
| return v.Kind() == reflect.Slice | |||||
| } | |||||
| if !v.Type().ConvertibleTo(dstType) { | |||||
| return false | |||||
| } | |||||
| // Handle converting to an integer type. | |||||
| dstInt, unsigned = isIntegerType(dstType) | |||||
| if dstInt { | |||||
| if isFloatType(v.Type()) { | |||||
| f = v.Float() | |||||
| if math.Trunc(f) != f || unsigned && f < 0 { | |||||
| return false | |||||
| } | |||||
| } | |||||
| srcInt, _ = isIntegerType(v.Type()) | |||||
| if srcInt && unsigned && v.Int() < 0 { | |||||
| return false | |||||
| } | |||||
| } | |||||
| return true | |||||
| } | |||||
| @ -1,3 +1,3 @@ | |||||
| #!/bin/sh | #!/bin/sh | ||||
| docker-compose exec server sh -c "cd /app && go test -v ./Api/Auth" | |||||
| docker-compose exec server sh -c "cd /app && go test -v ./..." | |||||