working commit

This commit is contained in:
2026-02-13 13:25:16 +02:00
parent c2d231c844
commit 930df60877
11 changed files with 343 additions and 37 deletions
+2 -1
View File
@@ -46,6 +46,7 @@ type Config struct {
Keypath string `json:"keypath,omitempty" yaml:"keypath"`
X509Cert string `json:"-" yaml:"-"`
X509Key string `json:"-" yaml:"-"`
Datadir string `json:"datadir"`
}
func NewConfig() *Config {
@@ -76,7 +77,7 @@ func NewConfig() *Config {
Logpath: logpath,
Runpath: runpath,
Version: version,
Datadir: datadir,
//Certpath: certpath,
//Keypath: keypath,
}
+23 -4
View File
@@ -10,12 +10,20 @@
package descr
const AnonymousID = "10000000-0000-0000-0000-000000000001"
const (
AnonimousUsername = "anonymous"
AnonymousID = "10000000-0000-0000-0000-000000000001"
ServerUsername = "server"
ServerID = "10000000-0000-0000-0000-000000000002"
InitUsername = "mstore"
InitID = "10000000-0000-0000-0000-000000000005"
)
type Grant struct {
ID string `json:"id" db:"id"`
AccountID string `json:"accountID" db:"account_id"`
Operation string `json:"operation" db:"operation"`
Right string `json:"right" db:"right"`
Pattern string `json:"pattern" db:"pattern"`
CreatedAt string `json:"createdAt" db:"created_at"`
UpdatedAt string `json:"updatedAt" db:"updated_at"`
@@ -24,7 +32,7 @@ type Grant struct {
}
type GrantShort struct {
Operation string `json:"operation" db:"operation"`
Right string `json:"right" db:"right"`
Pattern string `json:"pattern" db:"pattern"`
CreatedAt string `json:"createdAt" db:"created_at"`
UpdatedAt string `json:"updatedAt" db:"updated_at"`
@@ -33,5 +41,16 @@ type GrantShort struct {
}
const (
GrantCreateAccount = "createAccount"
// Accounts
RightReadAccounts = "readAccounts" // GetAccount, ListAccounts
RightWriteAccounts = "writeAccounts" // CreateAccount, UpdateAccount, DeleteAccount
// Frants
RightReadGrants = "readGrants" // Like account operation
RightWriteGrants = "writeGrants"
// Files
RightWriteFiles = "writeFiles" // FileInfo, GetFile, ListFiles
RightReadFiles = "readFiles" // PutFile, DeleteFile
// Images: manifests, layers
RightReadImages = "readImages" // ManifestInfo, GetManifest, BlobInfo, GetBlob
RightWriteImages = "writeImages" // other opearion
)
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package descr
type Server struct {
SchemeCreated bool `json:"SchemeCreated"`
AnonymousCreated bool `json:"AnonymousCreated"`
InituserCreated bool `json:"inituserCreated"`
SchemeCreatedAt string `json:"inituserCreatedAt"`
}
+8 -6
View File
@@ -9,10 +9,12 @@ import (
"mstore/app/router"
)
func (hand *Handler) CheckGrant(ctx context.Context, accountID, grant, subject string) (bool, error) {
func (hand *Handler) CheckRight(ctx context.Context, accountID, right, subject string) (bool, error) {
var err error
var res bool
hand.logg.Debugf("CheckRight %s: %s %s", accountID, right, subject)
res = true
return res, err
}
@@ -22,9 +24,13 @@ func (hand *Handler) CreateAccount(rctx *router.Context) {
params := &operator.CreateAccountParams{}
err = rctx.BindJSON(params)
if err != nil {
hand.SendError(rctx, err)
return
}
operatorID, _ := rctx.GetString(userTag)
opEnable, err := hand.CheckGrant(rctx.Ctx, operatorID, descr.GrantCreateAccount, params.Username)
opEnable, err := hand.CheckRight(rctx.Ctx, operatorID, descr.RightWriteAccounts, params.Username)
if err != nil {
err := fmt.Errorf("CreateAccount error: %v", err)
hand.SendError(rctx, err)
@@ -36,10 +42,6 @@ func (hand *Handler) CreateAccount(rctx *router.Context) {
return
}
if err != nil {
hand.SendError(rctx, err)
return
}
res, err := hand.oper.CreateAccount(rctx.Ctx, operatorID, params)
if err != nil {
hand.logg.Errorf("CreateAccount error: %v", err)
+9
View File
@@ -1,3 +1,12 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package handler
import (
+17 -8
View File
@@ -1,3 +1,12 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package maindb
import (
@@ -8,9 +17,9 @@ import (
func (db *Database) InsertGrant(ctx context.Context, grant *descr.Grant) error {
var err error
request := `INSERT INTO grants(id, account_id, operation, pattern, created_at, updated_at, created_by, updated_by)
request := `INSERT INTO grants(id, account_id, right, pattern, created_at, updated_at, created_by, updated_by)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`
_, err = db.db.Exec(request, grant.ID, grant.AccountID, grant.Operation, grant.Pattern,
_, err = db.db.Exec(request, grant.ID, grant.AccountID, grant.Right, grant.Pattern,
grant.CreatedAt, grant.UpdatedAt, grant.CreatedBy, grant.UpdatedBy)
if err != nil {
return err
@@ -67,12 +76,12 @@ func (db *Database) GetGrantByID(ctx context.Context, id string) (bool, *descr.G
return true, res, err
}
func (db *Database) GetGrantByAccoundIDOperationPattern(ctx context.Context, accountID, operation, pattern string) (bool, *descr.Grant, error) {
func (db *Database) GetGrantByAccoundIDRightPattern(ctx context.Context, accountID, right, pattern string) (bool, *descr.Grant, error) {
var err error
res := &descr.Grant{}
request := `SELECT * FROM grants WHERE account_id = $1 AND operation = $2 AND pattern = $3 LIMIT 1`
request := `SELECT * FROM grants WHERE account_id = $1 AND right = $2 AND pattern = $3 LIMIT 1`
dbRes := make([]descr.Grant, 0)
err = db.db.Select(&dbRes, request, accountID, operation, pattern)
err = db.db.Select(&dbRes, request, accountID, right, pattern)
if err != nil {
return false, res, err
}
@@ -84,10 +93,10 @@ func (db *Database) GetGrantByAccoundIDOperationPattern(ctx context.Context, acc
return true, res, err
}
func (db *Database) DeleteGrantByAccountIDOperationPattern(ctx context.Context, accountID, operation, pattern string) error {
func (db *Database) DeleteGrantByAccountIDRightPattern(ctx context.Context, accountID, right, pattern string) error {
var err error
request := `DELETE FROM grants WHERE account_id = $1 AND operation = $2 AND pattern = $3`
_, err = db.db.Exec(request, accountID, operation, pattern)
request := `DELETE FROM grants WHERE account_id = $1 AND right = $2 AND pattern = $3`
_, err = db.db.Exec(request, accountID, right, pattern)
if err != nil {
return err
}
+154
View File
@@ -0,0 +1,154 @@
/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package maindb
import (
"context"
"mstore/app/descr"
"mstore/pkg/auxpwd"
"mstore/pkg/auxtool"
"mstore/pkg/auxuuid"
)
func (db *Database) WriteAnonymous(ctx context.Context) error {
var err error
now := auxtool.TimeNow()
password := auxtool.RandomString(64)
passhash := auxpwd.MakeSHA256Hash([]byte(password))
accountDescr := &descr.Account{
ID: auxuuid.NewUUID(),
Username: descr.AnonimousUsername,
Passhash: passhash,
Disabled: false,
CreatedAt: now,
UpdatedAt: now,
CreatedBy: descr.ServerID,
UpdatedBy: descr.ServerID,
}
err = db.InsertAccount(ctx, accountDescr)
if err != nil {
return err
}
grantDescr := &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: accountDescr.ID,
Right: descr.RightReadFiles,
Pattern: "*",
CreatedAt: now,
UpdatedAt: now,
CreatedBy: descr.ServerID,
UpdatedBy: descr.ServerID,
}
err = db.InsertGrant(ctx, grantDescr)
if err != nil {
return err
}
grantDescr = &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: accountDescr.ID,
Right: descr.RightReadFiles,
Pattern: "*",
CreatedAt: now,
UpdatedAt: now,
CreatedBy: descr.ServerID,
UpdatedBy: descr.ServerID,
}
err = db.InsertGrant(ctx, grantDescr)
if err != nil {
return err
}
return err
}
func (db *Database) WriteInituser(ctx context.Context) error {
var err error
now := auxtool.TimeNow()
passhash := auxpwd.MakeSHA256Hash([]byte(descr.InitUsername))
accountDescr := &descr.Account{
ID: auxuuid.NewUUID(),
Username: descr.AnonimousUsername,
Passhash: passhash,
Disabled: false,
CreatedAt: now,
UpdatedAt: now,
CreatedBy: descr.ServerID,
UpdatedBy: descr.ServerID,
}
err = db.InsertAccount(ctx, accountDescr)
if err != nil {
return err
}
// Files
grantDescr := &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: accountDescr.ID,
Right: descr.RightReadFiles,
Pattern: "*",
CreatedAt: now,
UpdatedAt: now,
CreatedBy: descr.ServerID,
UpdatedBy: descr.ServerID,
}
err = db.InsertGrant(ctx, grantDescr)
if err != nil {
return err
}
grantDescr = &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: accountDescr.ID,
Right: descr.RightWriteFiles,
Pattern: "*",
CreatedAt: now,
UpdatedAt: now,
CreatedBy: descr.ServerID,
UpdatedBy: descr.ServerID,
}
err = db.InsertGrant(ctx, grantDescr)
if err != nil {
return err
}
// Images
grantDescr = &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: accountDescr.ID,
Right: descr.RightReadImages,
Pattern: "*",
CreatedAt: now,
UpdatedAt: now,
CreatedBy: descr.ServerID,
UpdatedBy: descr.ServerID,
}
err = db.InsertGrant(ctx, grantDescr)
if err != nil {
return err
}
grantDescr = &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: accountDescr.ID,
Right: descr.RightWriteImages,
Pattern: "*",
CreatedAt: now,
UpdatedAt: now,
CreatedBy: descr.ServerID,
UpdatedBy: descr.ServerID,
}
err = db.InsertGrant(ctx, grantDescr)
if err != nil {
return err
}
return err
}
+10 -2
View File
@@ -110,8 +110,12 @@ func (oper *Operator) GetAccount(ctx context.Context, params *GetAccountParams)
}
for _, grantDescrs := range grantDescrs {
grantShorts := descr.GrantShort{
Operation: grantDescrs.Operation,
Right: grantDescrs.Right,
Pattern: grantDescrs.Pattern,
CreatedAt: grantDescrs.CreatedAt,
UpdatedAt: grantDescrs.UpdatedAt,
CreatedBy: grantDescrs.CreatedBy,
UpdatedBy: grantDescrs.UpdatedBy,
}
accountShort.Grants = append(accountShort.Grants, grantShorts)
}
@@ -253,8 +257,12 @@ func (oper *Operator) ListAccounts(ctx context.Context, params *ListAccountsPara
}
for _, grantDescrs := range grantDescrs {
grantShorts := descr.GrantShort{
Operation: grantDescrs.Operation,
Right: grantDescrs.Right,
Pattern: grantDescrs.Pattern,
CreatedAt: grantDescrs.CreatedAt,
UpdatedAt: grantDescrs.UpdatedAt,
CreatedBy: grantDescrs.CreatedBy,
UpdatedBy: grantDescrs.UpdatedBy,
}
accountShort.Grants = append(accountShort.Grants, grantShorts)
}
+4 -4
View File
@@ -11,7 +11,7 @@ import (
type CreateGrantParams struct {
AccountID string `json:"accountID"`
Operation string `json:"operation"`
Right string `json:"operation"`
Pattern string `json:"pattern"`
}
type CreateGrantResult struct {
@@ -26,7 +26,7 @@ func (oper *Operator) CreateGrant(ctx context.Context, params *CreateGrantParams
err := fmt.Errorf("Empty accountId parameters")
return res, err
}
if params.Operation == "" {
if params.Right == "" {
err := fmt.Errorf("Empty operation parameter")
return res, err
}
@@ -35,7 +35,7 @@ func (oper *Operator) CreateGrant(ctx context.Context, params *CreateGrantParams
return res, err
}
grantExists, _, err := oper.mdb.GetGrantByAccoundIDOperationPattern(ctx, params.AccountID, params.Operation, params.Pattern)
grantExists, _, err := oper.mdb.GetGrantByAccoundIDRightPattern(ctx, params.AccountID, params.Right, params.Pattern)
if err != nil {
return res, err
}
@@ -47,7 +47,7 @@ func (oper *Operator) CreateGrant(ctx context.Context, params *CreateGrantParams
grantDescr := &descr.Grant{
ID: auxuuid.NewUUID(),
AccountID: params.AccountID,
Operation: params.Operation,
Right: params.Right,
Pattern: params.Pattern,
CreatedAt: now,
UpdatedAt: now,
+71 -12
View File
@@ -11,20 +11,26 @@
package server
import (
"context"
"io/ioutil"
"os"
"os/signal"
"os/user"
"path/filepath"
"strconv"
"syscall"
"time"
"mstore/app/config"
"mstore/app/descr"
"mstore/app/handler"
"mstore/app/logger"
"mstore/app/maindb"
"mstore/app/operator"
"mstore/app/service"
"mstore/app/storage"
"sigs.k8s.io/yaml"
)
type Server struct {
@@ -35,6 +41,7 @@ type Server struct {
hand *handler.Handler
logg *logger.Logger
stor *storage.Storage
stat descr.Server
}
func NewServer() (*Server, error) {
@@ -95,50 +102,102 @@ func (srv *Server) Configure() error {
func (srv *Server) Build() error {
var err error
srv.logg.Infof("Server build")
srv.logg.Infof("Server building")
confDump := srv.conf.String()
srv.logg.Infof("Current server configuration is:\n%s\n", confDump)
if srv.conf.AsDaemon {
logdir := filepath.Dir(srv.conf.Logpath)
srv.logg.Infof("Create log directory %s", logdir)
srv.logg.Infof("Creating log directory %s", logdir)
err = os.MkdirAll(logdir, 0750)
if err != nil {
return err
}
rundir := filepath.Dir(srv.conf.Runpath)
srv.logg.Infof("Create run directory %s", rundir)
srv.logg.Infof("Creating run directory %s", rundir)
err = os.MkdirAll(rundir, 0750)
if err != nil {
return err
}
}
// Creating datadir
datadir := srv.conf.Datadir
srv.logg.Infof("Creating data directory %s ", datadir)
err = os.MkdirAll(datadir, 0750)
if err != nil {
return err
}
// Read state file
statefilePath := filepath.Join(srv.conf.Datadir, "server.yaml")
stateData, err := ioutil.ReadFile(statefilePath)
if err != nil {
err = yaml.Unmarshal(stateData, &srv.stat)
if err != nil {
return err
}
}
// Creating database
dbdir := srv.conf.Database.Basepath
srv.logg.Infof("Create database directory %s ", dbdir)
srv.logg.Infof("Creating database directory %s ", dbdir)
err = os.MkdirAll(dbdir, 0750)
if err != nil {
return err
}
mdb := maindb.NewDatabase(dbdir)
srv.logg.Infof("Open main database")
srv.logg.Infof("Opening main database")
err = mdb.OpenDatabase()
if err != nil {
return err
}
srv.logg.Infof("Initialize main database")
err = mdb.InitDatabase()
if err != nil {
return err
}
srv.mdb = mdb
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
// Created db scheme
if !srv.stat.SchemeCreated {
srv.logg.Infof("Initialize main database")
err = mdb.InitDatabase()
if err != nil {
return err
}
srv.stat.SchemeCreated = true
}
// Created anonymous user
if !srv.stat.AnonymousCreated {
srv.logg.Infof("Creating anonimous user")
err = mdb.WriteAnonymous(ctx)
if err != nil {
return err
}
srv.stat.AnonymousCreated = true
}
if !srv.stat.InituserCreated {
srv.logg.Infof("Creating init user")
err = srv.mdb.WriteAnonymous(ctx)
if err != nil {
return err
}
srv.stat.InituserCreated = true
}
// Write status file
stateData, err = yaml.Marshal(srv.stat)
if err != nil {
return err
}
err = ioutil.WriteFile(statefilePath, stateData, 0640)
if err != nil {
return err
}
// Creating storage
srv.logg.Infof("Create storage directory")
datadir := srv.conf.Database.Basepath
srv.logg.Infof("Creating storage directory")
datadir = srv.conf.Database.Basepath
err = os.MkdirAll(datadir, 0750)
if err != nil {
return err