2024-08-17 21:57:14 +02:00
package service
2024-08-12 11:00:25 +02:00
import (
"crypto/ecdsa"
"crypto/x509"
"encoding/base64"
2024-08-17 21:57:14 +02:00
"fmt"
"github.com/fxamacker/cbor/v2"
2024-08-12 11:00:25 +02:00
"log"
"os"
"time"
"github.com/go-webauthn/webauthn/protocol"
2024-08-17 21:57:14 +02:00
"github.com/stonith404/pocket-id/backend/internal/common"
"github.com/stonith404/pocket-id/backend/internal/model"
"github.com/stonith404/pocket-id/backend/internal/utils"
2024-08-12 11:00:25 +02:00
"gorm.io/gorm"
)
2024-08-17 21:57:14 +02:00
type TestService struct {
db * gorm . DB
appConfigService * AppConfigService
2024-08-12 11:00:25 +02:00
}
2024-08-17 21:57:14 +02:00
func NewTestService ( db * gorm . DB , appConfigService * AppConfigService ) * TestService {
return & TestService { db : db , appConfigService : appConfigService }
2024-08-12 11:00:25 +02:00
}
2024-08-17 21:57:14 +02:00
func ( s * TestService ) SeedDatabase ( ) error {
return s . db . Transaction ( func ( tx * gorm . DB ) error {
2024-08-12 11:00:25 +02:00
users := [ ] model . User {
{
Base : model . Base {
ID : "f4b89dc2-62fb-46bf-9f5f-c34f4eafe93e" ,
} ,
Username : "tim" ,
Email : "tim.cook@test.com" ,
FirstName : "Tim" ,
LastName : "Cook" ,
IsAdmin : true ,
} ,
{
Base : model . Base {
ID : "1cd19686-f9a6-43f4-a41f-14a0bf5b4036" ,
} ,
Username : "craig" ,
Email : "craig.federighi@test.com" ,
FirstName : "Craig" ,
LastName : "Federighi" ,
IsAdmin : false ,
} ,
}
for _ , user := range users {
if err := tx . Create ( & user ) . Error ; err != nil {
return err
}
}
oidcClients := [ ] model . OidcClient {
{
Base : model . Base {
ID : "3654a746-35d4-4321-ac61-0bdcff2b4055" ,
} ,
2024-08-23 17:04:19 +02:00
Name : "Nextcloud" ,
Secret : "$2a$10$9dypwot8nGuCjT6wQWWpJOckZfRprhe2EkwpKizxS/fpVHrOLEJHC" , // w2mUeZISmEvIDMEDvpY0PnxQIpj1m3zY
CallbackURLs : model . CallbackURLs { "http://nextcloud/auth/callback" } ,
ImageType : utils . StringPointer ( "png" ) ,
CreatedByID : users [ 0 ] . ID ,
2024-08-12 11:00:25 +02:00
} ,
{
Base : model . Base {
ID : "606c7782-f2b1-49e5-8ea9-26eb1b06d018" ,
} ,
2024-08-23 17:04:19 +02:00
Name : "Immich" ,
Secret : "$2a$10$Ak.FP8riD1ssy2AGGbG.gOpnp/rBpymd74j0nxNMtW0GG1Lb4gzxe" , // PYjrE9u4v9GVqXKi52eur0eb2Ci4kc0x
CallbackURLs : model . CallbackURLs { "http://immich/auth/callback" } ,
CreatedByID : users [ 0 ] . ID ,
2024-08-12 11:00:25 +02:00
} ,
}
for _ , client := range oidcClients {
if err := tx . Create ( & client ) . Error ; err != nil {
return err
}
}
authCode := model . OidcAuthorizationCode {
Code : "auth-code" ,
Scope : "openid profile" ,
Nonce : "nonce" ,
ExpiresAt : time . Now ( ) . Add ( 1 * time . Hour ) ,
UserID : users [ 0 ] . ID ,
ClientID : oidcClients [ 0 ] . ID ,
}
if err := tx . Create ( & authCode ) . Error ; err != nil {
return err
}
accessToken := model . OneTimeAccessToken {
Token : "one-time-token" ,
ExpiresAt : time . Now ( ) . Add ( 1 * time . Hour ) ,
UserID : users [ 0 ] . ID ,
}
if err := tx . Create ( & accessToken ) . Error ; err != nil {
return err
}
userAuthorizedClient := model . UserAuthorizedOidcClient {
Scope : "openid profile email" ,
UserID : users [ 0 ] . ID ,
ClientID : oidcClients [ 0 ] . ID ,
}
if err := tx . Create ( & userAuthorizedClient ) . Error ; err != nil {
return err
}
2024-08-17 21:57:14 +02:00
publicKey1 , err := getCborPublicKey ( "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwcOo5KV169KR67QEHrcYkeXE3CCxv2BgwnSq4VYTQxyLtdmKxegexa8JdwFKhKXa2BMI9xaN15BoL6wSCRFJhg==" )
publicKey2 , err := getCborPublicKey ( "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESq/wR8QbBu3dKnpaw/v0mDxFFDwnJ/L5XHSg2tAmq5x1BpSMmIr3+DxCbybVvGRmWGh8kKhy7SMnK91M6rFHTA==" )
if err != nil {
return err
}
2024-08-12 11:00:25 +02:00
webauthnCredentials := [ ] model . WebauthnCredential {
{
Name : "Passkey 1" ,
CredentialID : "test-credential-1" ,
2024-08-17 21:57:14 +02:00
PublicKey : publicKey1 ,
2024-08-12 11:00:25 +02:00
AttestationType : "none" ,
Transport : model . AuthenticatorTransportList { protocol . Internal } ,
UserID : users [ 0 ] . ID ,
} ,
{
Name : "Passkey 2" ,
CredentialID : "test-credential-2" ,
2024-08-17 21:57:14 +02:00
PublicKey : publicKey2 ,
2024-08-12 11:00:25 +02:00
AttestationType : "none" ,
Transport : model . AuthenticatorTransportList { protocol . Internal } ,
UserID : users [ 0 ] . ID ,
} ,
}
for _ , credential := range webauthnCredentials {
if err := tx . Create ( & credential ) . Error ; err != nil {
return err
}
}
webauthnSession := model . WebauthnSession {
Challenge : "challenge" ,
ExpiresAt : time . Now ( ) . Add ( 1 * time . Hour ) ,
UserVerification : "preferred" ,
}
if err := tx . Create ( & webauthnSession ) . Error ; err != nil {
return err
}
return nil
} )
}
2024-08-17 21:57:14 +02:00
func ( s * TestService ) ResetDatabase ( ) error {
err := s . db . Transaction ( func ( tx * gorm . DB ) error {
2024-08-12 11:00:25 +02:00
var tables [ ] string
if err := tx . Raw ( "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != 'schema_migrations';" ) . Scan ( & tables ) . Error ; err != nil {
return err
}
for _ , table := range tables {
if err := tx . Exec ( "DELETE FROM " + table ) . Error ; err != nil {
return err
}
}
return nil
} )
if err != nil {
return err
}
2024-08-17 21:57:14 +02:00
err = s . appConfigService . InitDbConfig ( )
return err
2024-08-12 11:00:25 +02:00
}
2024-08-17 21:57:14 +02:00
func ( s * TestService ) ResetApplicationImages ( ) error {
2024-08-12 11:00:25 +02:00
if err := os . RemoveAll ( common . EnvConfig . UploadPath ) ; err != nil {
log . Printf ( "Error removing directory: %v" , err )
return err
}
if err := utils . CopyDirectory ( "./images" , common . EnvConfig . UploadPath + "/application-images" ) ; err != nil {
log . Printf ( "Error copying directory: %v" , err )
return err
}
return nil
}
// getCborPublicKey decodes a Base64 encoded public key and returns the CBOR encoded COSE key
2024-08-17 21:57:14 +02:00
func getCborPublicKey ( base64PublicKey string ) ( [ ] byte , error ) {
2024-08-12 11:00:25 +02:00
decodedKey , err := base64 . StdEncoding . DecodeString ( base64PublicKey )
if err != nil {
2024-08-17 21:57:14 +02:00
return nil , fmt . Errorf ( "failed to decode base64 key: %w" , err )
2024-08-12 11:00:25 +02:00
}
pubKey , err := x509 . ParsePKIXPublicKey ( decodedKey )
if err != nil {
2024-08-17 21:57:14 +02:00
return nil , fmt . Errorf ( "failed to parse public key: %w" , err )
2024-08-12 11:00:25 +02:00
}
ecdsaPubKey , ok := pubKey . ( * ecdsa . PublicKey )
if ! ok {
2024-08-17 21:57:14 +02:00
return nil , fmt . Errorf ( "not an ECDSA public key" )
2024-08-12 11:00:25 +02:00
}
coseKey := map [ int ] interface { } {
1 : 2 , // Key type: EC2
3 : - 7 , // Algorithm: ECDSA with SHA-256
- 1 : 1 , // Curve: P-256
- 2 : ecdsaPubKey . X . Bytes ( ) , // X coordinate
- 3 : ecdsaPubKey . Y . Bytes ( ) , // Y coordinate
}
cborPublicKey , err := cbor . Marshal ( coseKey )
if err != nil {
2024-08-17 21:57:14 +02:00
return nil , fmt . Errorf ( "failed to marshal COSE key: %w" , err )
2024-08-12 11:00:25 +02:00
}
2024-08-17 21:57:14 +02:00
return cborPublicKey , nil
2024-08-12 11:00:25 +02:00
}