@ -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 | |||
docker-compose exec server sh -c "cd /app && go test -v ./Api/Auth" | |||
docker-compose exec server sh -c "cd /app && go test -v ./..." |