added addAccount endpoint

This commit is contained in:
Roland Osborne 2022-01-16 21:11:24 -08:00
parent a5a02d7abb
commit 1c3518424a
14 changed files with 265 additions and 57 deletions

View File

@ -75,7 +75,7 @@ paths:
description: Set admin password and node domain description: Set admin password and node domain
operationId: set-node-claim operationId: set-node-claim
security: security:
- basicAuth: [] - basicCredentials: []
parameters: parameters:
- name: domain - name: domain
in: query in: query
@ -302,7 +302,7 @@ paths:
operationId: add-public-account operationId: add-public-account
security: security:
- bearerAuth: [] - bearerAuth: []
- basicAuth: [] - basicCredentials: []
responses: responses:
'201': '201':
description: successful operation description: successful operation
@ -431,7 +431,7 @@ paths:
operationId: add-account operationId: add-account
security: security:
- bearerAuth: [] - bearerAuth: []
- basicAuth: [] - basicCredentials: []
responses: responses:
'201': '201':
description: successful operation description: successful operation
@ -3964,11 +3964,11 @@ components:
Profile: Profile:
type: object type: object
required: required:
- profileId - guid
- revision - revision
- node - node
properties: properties:
profileId: guid:
type: string type: string
handle: handle:
type: string type: string
@ -4468,7 +4468,11 @@ components:
basicAuth: basicAuth:
type: http type: http
scheme: basic scheme: basic
basicCredentials:
type: http
schema
bearerAuth: bearerAuth:
type: http type: http
scheme: bearer scheme: bearer

View File

@ -7,7 +7,10 @@ require (
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.3 // indirect github.com/jinzhu/now v1.1.3 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-sqlite3 v1.14.9 // indirect github.com/mattn/go-sqlite3 v1.14.9 // indirect
github.com/rogpeppe/go-internal v1.6.1 // indirect
github.com/theckman/go-securerandom v0.1.1 // indirect github.com/theckman/go-securerandom v0.1.1 // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
gorm.io/driver/sqlite v1.2.6 // indirect gorm.io/driver/sqlite v1.2.6 // indirect

View File

@ -1,3 +1,4 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
@ -9,9 +10,18 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI= github.com/jinzhu/now v1.1.3 h1:PlHq1bSCSZL9K0wUhbm2pGLoTWs2GwVhsP6emvGV/ZI=
github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.3/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ= github.com/theckman/go-securerandom v0.1.1 h1:5KctSyM0D5KKFK+bsypIyLq7yik0CEaI5i2fGcUGcsQ=
@ -19,6 +29,8 @@ github.com/theckman/go-securerandom v0.1.1/go.mod h1:bmkysLfBH6i891sBpcP4xRM3XIB
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4= gorm.io/driver/sqlite v1.2.6 h1:SStaH/b+280M7C8vXeZLz/zo9cLQmIGwwj3cSj7p6l4=
gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY= gorm.io/driver/sqlite v1.2.6/go.mod h1:gyoX0vHiiwi0g49tv+x2E7l8ksauLK0U/gShcdUsjWY=

View File

@ -0,0 +1,77 @@
package databag
import (
"net/http"
"crypto/sha256"
"encoding/hex"
"databag/internal/store"
)
func AddAccount(w http.ResponseWriter, r *http.Request) {
if _, err := bearerAccountToken(r); err != nil {
LogMsg("authentication failed")
w.WriteHeader(http.StatusUnauthorized)
return
}
username, password, err := basicCredentials(r);
if err != nil {
LogMsg("invalid basic credentials")
w.WriteHeader(http.StatusUnauthorized)
return
}
// generate account key
privateKey, publicKey := GenerateRsaKeyPair()
privatePem := ExportRsaPrivateKeyAsPemStr(privateKey)
publicPem, err := ExportRsaPublicKeyAsPemStr(publicKey)
if err != nil {
LogMsg("failed generate key")
w.WriteHeader(http.StatusInternalServerError)
return
}
// compute key fingerprint
msg := []byte(publicPem)
hash := sha256.New()
if _, err = hash.Write(msg); err != nil {
LogMsg("failed to fingerprint key")
w.WriteHeader(http.StatusInternalServerError)
return
}
fingerprint := hex.EncodeToString(hash.Sum(nil))
// create new account
account := store.Account{
PublicKey: publicPem,
PrivateKey: privatePem,
KeyType: "RSA4096",
Username: username,
Password: password,
Guid: fingerprint,
};
if res := store.DB.Create(&account).Error; res != nil {
LogMsg("failed to store account")
w.WriteHeader(http.StatusInternalServerError)
return
}
// create response
profile := Profile{
Guid: account.Guid,
Handle: account.Username,
Name: account.Name,
Description: account.Description,
Location: account.Location,
Image: account.Image,
Revision: account.ProfileRevision,
Version: CONFIG_VERSION,
Node: "https://" + getStrConfigValue(CONFIG_DOMAIN, ""),
}
// send response
WriteResponse(w, profile)
}

View File

@ -14,11 +14,11 @@ func TestAccount(t *testing.T) {
r := httptest.NewRequest("POST", "/admin/accounts", nil) r := httptest.NewRequest("POST", "/admin/accounts", nil)
r.Header.Add("Authorization","Basic " + auth) r.Header.Add("Authorization","Basic " + auth)
w := httptest.NewRecorder() w := httptest.NewRecorder()
AddNodeAccount(w, r); AddNodeAccount(w, r)
resp := w.Result(); resp := w.Result()
dec := json.NewDecoder(resp.Body); dec := json.NewDecoder(resp.Body)
var token string; var token string
dec.Decode(&token); dec.Decode(&token)
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
t.Errorf("failed to create account") t.Errorf("failed to create account")
return return
@ -28,36 +28,55 @@ func TestAccount(t *testing.T) {
r = httptest.NewRequest("GET", "/account/token", nil) r = httptest.NewRequest("GET", "/account/token", nil)
r.Header.Add("Authorization","Bearer " + token) r.Header.Add("Authorization","Bearer " + token)
w = httptest.NewRecorder() w = httptest.NewRecorder()
GetAccountToken(w, r); GetAccountToken(w, r)
resp = w.Result(); resp = w.Result()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
t.Errorf("invalid token value") t.Errorf("invalid token value")
return return
} }
dec = json.NewDecoder(resp.Body); dec = json.NewDecoder(resp.Body)
var tokenType string; var tokenType string
dec.Decode(&tokenType); dec.Decode(&tokenType)
if tokenType != "create" { if tokenType != "create" {
t.Errorf("invalid token type") t.Errorf("invalid token type")
return return
} }
// check if username is available // check if username is available
r = httptest.NewRequest("GET", "/account/claimable?username=databag", nil) r = httptest.NewRequest("GET", "/account/claimable?username=user", nil)
r.Header.Add("Authorization","Bearer " + token) r.Header.Add("Authorization","Bearer " + token)
w = httptest.NewRecorder() w = httptest.NewRecorder()
GetAccountUsername(w, r); GetAccountUsername(w, r)
resp = w.Result(); resp = w.Result()
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
t.Errorf("invalid token value") t.Errorf("invalid token value")
return return
} }
dec = json.NewDecoder(resp.Body); dec = json.NewDecoder(resp.Body)
var available bool; var available bool
dec.Decode(&available); dec.Decode(&available)
if !available { if !available {
t.Errorf("username not available") t.Errorf("username not available")
return return
} }
// create account
auth = base64.StdEncoding.EncodeToString([]byte("user:pass"))
r = httptest.NewRequest("GET", "/account/profile", nil)
r.Header.Add("Credentials","Basic " + auth)
r.Header.Add("Authorization","Bearer " + token)
w = httptest.NewRecorder()
AddAccount(w, r)
resp = w.Result()
if resp.StatusCode != 200 {
t.Errorf("invalid token value")
return
}
dec = json.NewDecoder(resp.Body)
var profile Profile
dec.Decode(&profile)
if profile.Guid == nil {
t.Errorf("invalid profile")
return
}
} }

View File

@ -13,11 +13,6 @@ import (
"net/http" "net/http"
) )
func AddAccount(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
}
func AddAccountApp(w http.ResponseWriter, r *http.Request) { func AddAccountApp(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8") w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)

View File

@ -0,0 +1,83 @@
package databag
import (
"errors"
"strings"
"net/http"
"encoding/base64"
"golang.org/x/crypto/bcrypt"
"databag/internal/store"
)
func adminLogin(r *http.Request) bool {
// extract request auth
username, password, ok := r.BasicAuth();
if !ok || username == "" || password == "" {
return false
}
// nothing to do if not configured
if !getBoolConfigValue(CONFIG_CONFIGURED, false) {
return false;
}
// compare username
if getStrConfigValue(CONFIG_USERNAME, "") != username {
return false
}
// compare password
p := getBinConfigValue(CONFIG_PASSWORD, nil);
if bcrypt.CompareHashAndPassword(p, []byte(password)) != nil {
return false
}
return true;
}
func bearerAccountToken(r *http.Request) (store.AccountToken, error) {
// parse bearer authentication
auth := r.Header.Get("Authorization")
token := strings.TrimSpace(strings.TrimPrefix(auth, "Bearer"))
// find token record
var accountToken store.AccountToken
err := store.DB.Where("token = ?", token).First(&accountToken).Error
return accountToken, err
}
func basicCredentials(r *http.Request) (string, []byte, error) {
var username string
var password []byte
// parse bearer authentication
auth := r.Header.Get("Credentials")
token := strings.TrimSpace(strings.TrimPrefix(auth, "Basic"))
// decode basic auth
credentials, err := base64.StdEncoding.DecodeString(token)
if err != nil {
LogMsg("faield to decode basic credentials");
return username, password, err
}
// parse credentials
login := strings.Split(string(credentials), ":");
if login[0] == "" || login[1] == "" {
LogMsg("failed to parse basic credentials");
return username, password, errors.New("invalid credentials")
}
username = login[0]
// hash password
password, err = bcrypt.GenerateFromPassword([]byte(login[1]), bcrypt.DefaultCost)
if err != nil {
LogMsg("failed to hash password")
return username, password, err
}
return username, password, nil
}

View File

@ -1,6 +1,7 @@
package databag package databag
const CONFIG_BODYLIMIT = 1048576 const CONFIG_BODYLIMIT = 1048576
const CONFIG_VERSION = "0.0.1"
const CONFIG_CONFIGURED = "configured" const CONFIG_CONFIGURED = "configured"
const CONFIG_USERNAME = "username" const CONFIG_USERNAME = "username"

View File

@ -16,6 +16,7 @@ import (
"os" "os"
"runtime" "runtime"
"strings" "strings"
"github.com/kr/pretty"
) )
func Logger(inner http.Handler, name string) http.Handler { func Logger(inner http.Handler, name string) http.Handler {
@ -39,3 +40,7 @@ func LogMsg(msg string) {
p, _ := os.Getwd() p, _ := os.Getwd()
log.Printf("%s:%d %s", strings.TrimPrefix(file, p), line, msg) log.Printf("%s:%d %s", strings.TrimPrefix(file, p), line, msg)
} }
func PrintMsg(obj interface{}) {
pretty.Println(obj);
}

View File

@ -43,11 +43,10 @@ func Claimable() {
func Claim() { func Claim() {
auth := base64.StdEncoding.EncodeToString([]byte("admin:pass")) auth := base64.StdEncoding.EncodeToString([]byte("admin:pass"))
r := httptest.NewRequest("PUT", "/admin/claim", nil) r := httptest.NewRequest("PUT", "/admin/claim", nil)
r.Header.Add("Authorization","Basic " + auth) r.Header.Add("Credentials","Basic " + auth)
w := httptest.NewRecorder() w := httptest.NewRecorder()
SetNodeClaim(w, r) SetNodeClaim(w, r)
if w.Code != 200 { if w.Code != 200 {
LogMsg("HERE");
panic("server not initially claimable") panic("server not initially claimable")
} }
} }

View File

@ -230,7 +230,7 @@ type NodeConfig struct {
} }
type Profile struct { type Profile struct {
ProfileId string `json:"profileId"` Guid string `json:"profileId"`
Handle string `json:"handle,omitempty"` Handle string `json:"handle,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`

View File

@ -5,7 +5,6 @@ import (
"net/http" "net/http"
"gorm.io/gorm" "gorm.io/gorm"
"databag/internal/store" "databag/internal/store"
"golang.org/x/crypto/bcrypt"
) )
func SetNodeClaim(w http.ResponseWriter, r *http.Request) { func SetNodeClaim(w http.ResponseWriter, r *http.Request) {
@ -21,24 +20,18 @@ func SetNodeClaim(w http.ResponseWriter, r *http.Request) {
return return
} }
username, password, ok := r.BasicAuth(); username, password, res := basicCredentials(r);
if !ok || username == "" || password == "" { if res != nil {
LogMsg("SetNodeClaim - invalid credenitals"); LogMsg("invalid credenitals");
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
return return
} }
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
LogMsg("SetNodeClaim - failed to hash password");
w.WriteHeader(http.StatusInternalServerError)
return
}
err = store.DB.Transaction(func(tx *gorm.DB) error { err = store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Create(&store.Config{ConfigId: CONFIG_USERNAME, StrValue: username}).Error; res != nil { if res := tx.Create(&store.Config{ConfigId: CONFIG_USERNAME, StrValue: username}).Error; res != nil {
return res return res
} }
if res := tx.Create(&store.Config{ConfigId: CONFIG_PASSWORD, BinValue: hashedPassword}).Error; res != nil { if res := tx.Create(&store.Config{ConfigId: CONFIG_PASSWORD, BinValue: password}).Error; res != nil {
return res return res
} }
if res := tx.Create(&store.Config{ConfigId: CONFIG_CONFIGURED, BoolValue: true}).Error; res != nil { if res := tx.Create(&store.Config{ConfigId: CONFIG_CONFIGURED, BoolValue: true}).Error; res != nil {

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause"
"databag/internal/store" "databag/internal/store"
) )
@ -30,15 +31,31 @@ func SetNodeConfig(w http.ResponseWriter, r *http.Request) {
// store credentials // store credentials
err := store.DB.Transaction(func(tx *gorm.DB) error { err := store.DB.Transaction(func(tx *gorm.DB) error {
if res := tx.Create(&store.Config{ConfigId: CONFIG_DOMAIN, StrValue: config.Domain}).Error; res != nil {
// upsert domain config
if res := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "config_id"}},
DoUpdates: clause.AssignmentColumns([]string{"str_value"}),
}).Create(&store.Config{ConfigId: CONFIG_DOMAIN, StrValue: config.Domain}).Error; res != nil {
return res return res
} }
if res := tx.Create(&store.Config{ConfigId: CONFIG_PUBLICLIMIT, NumValue: config.PublicLimit}).Error; res != nil {
// upsert public limit config
if res := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "config_id"}},
DoUpdates: clause.AssignmentColumns([]string{"num_value"}),
}).Create(&store.Config{ConfigId: CONFIG_PUBLICLIMIT, NumValue: config.PublicLimit}).Error; res != nil {
return res return res
} }
if res := tx.Create(&store.Config{ConfigId: CONFIG_STORAGE, NumValue: config.AccountStorage}).Error; res != nil {
// upsert account storage config
if res := tx.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "config_id"}},
DoUpdates: clause.AssignmentColumns([]string{"num_value"}),
}).Create(&store.Config{ConfigId: CONFIG_STORAGE, NumValue: config.AccountStorage}).Error; res != nil {
return res return res
} }
return nil; return nil;
}) })
if(err != nil) { if(err != nil) {

View File

@ -46,24 +46,24 @@ type AccountToken struct {
type Account struct { type Account struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"` ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
PublicKey []byte `gorm:"not null"` PublicKey string `gorm:"not null"`
PrivateKey []byte `gorm:"not null"` PrivateKey string `gorm:"not null"`
KeyType []byte `gorm:"not null"` KeyType string `gorm:"not null"`
ProfileId string `gorm:"not null;uniqueIndex"` Guid string `gorm:"not null;uniqueIndex"`
Username string `gorm:"not null;uniqueIndex"` Username string `gorm:"not null;uniqueIndex"`
Password []byte `gorm:"not null"` Password []byte `gorm:"not null"`
Name string Name string
Description string Description string
Location string Location string
Image string Image string
ProfileRevision int64 `gorm:"not null"` ProfileRevision int64 `gorm:"not null;default:1"`
ContentRevision int64 `gorm:"not null"` ContentRevision int64 `gorm:"not null;default:1"`
ViewRevision int64 `gorm:"not null"` ViewRevision int64 `gorm:"not null;default:1"`
GroupRevision int64 `gorm:"not null"` GroupRevision int64 `gorm:"not null;default:1"`
LabelRevision int64 `gorm:"not null"` LabelRevision int64 `gorm:"not null;default:1"`
CardRevision int64 `gorm:"not null"` CardRevision int64 `gorm:"not null;default:1"`
DialogueRevision int64 `gorm:"not null"` DialogueRevision int64 `gorm:"not null;default:1"`
InsightRevision uint64 `gorm:"not null"` InsightRevision uint64 `gorm:"not null;default:1"`
Created int64 `gorm:"autoCreateTime"` Created int64 `gorm:"autoCreateTime"`
Apps []App Apps []App
} }
@ -108,7 +108,7 @@ type Card struct {
ID uint `gorm:"primaryKey;not null;unique;autoIncrement"` ID uint `gorm:"primaryKey;not null;unique;autoIncrement"`
CardId string `gorm:"not null;index:card,unique"` CardId string `gorm:"not null;index:card,unique"`
AccountID uint `gorm:"not null;index:card,unique"` AccountID uint `gorm:"not null;index:card,unique"`
DID string `gorm:"not null"` GUID string `gorm:"not null"`
Username string Username string
Name string Name string
Description string Description string