mirror of
https://github.com/luxfi/mpc.git
synced 2026-09-24 00:26:24 +00:00
fix: gofmt -s across repo (CI format check)
This commit is contained in:
+2
-2
@@ -72,7 +72,7 @@ func (s *Server) validateJWT(tokenStr string) (*JWTClaims, error) {
|
||||
if claims.Issuer != "mpc.lux.network" {
|
||||
return nil, fmt.Errorf("invalid token issuer")
|
||||
}
|
||||
if !slices.Contains([]string(claims.Audience),"mpc-api") {
|
||||
if !slices.Contains([]string(claims.Audience), "mpc-api") {
|
||||
return nil, fmt.Errorf("invalid token audience")
|
||||
}
|
||||
return claims, nil
|
||||
@@ -95,7 +95,7 @@ func (s *Server) validateRefreshToken(tokenStr string) (*JWTClaims, error) {
|
||||
if claims.Issuer != "mpc.lux.network" {
|
||||
return nil, fmt.Errorf("invalid token issuer")
|
||||
}
|
||||
if !slices.Contains([]string(claims.Audience),"mpc-refresh") {
|
||||
if !slices.Contains([]string(claims.Audience), "mpc-refresh") {
|
||||
return nil, fmt.Errorf("invalid token audience")
|
||||
}
|
||||
return claims, nil
|
||||
|
||||
@@ -38,10 +38,10 @@ type approvalSession struct {
|
||||
CreatedAt time.Time
|
||||
ExpiresAt time.Time
|
||||
|
||||
mu sync.Mutex
|
||||
sigs []approval.ApprovalSignature
|
||||
completed bool
|
||||
rejected bool
|
||||
mu sync.Mutex
|
||||
sigs []approval.ApprovalSignature
|
||||
completed bool
|
||||
rejected bool
|
||||
rejectReason string
|
||||
}
|
||||
|
||||
@@ -393,9 +393,9 @@ func (s *Server) handleApprovalCast(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"status": ifElseString(sess.completed, "approved", "pending"),
|
||||
"collected": len(sess.sigs),
|
||||
"threshold": sess.Threshold,
|
||||
"status": ifElseString(sess.completed, "approved", "pending"),
|
||||
"collected": len(sess.sigs),
|
||||
"threshold": sess.Threshold,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+16
-16
@@ -16,16 +16,16 @@ import (
|
||||
|
||||
// ValidatorKeySet holds MPC wallet references for a validator's BLS and Corona keys.
|
||||
type ValidatorKeySet struct {
|
||||
ValidatorID string `json:"validatorId"`
|
||||
BLSWalletID string `json:"blsWalletId"`
|
||||
ValidatorID string `json:"validatorId"`
|
||||
BLSWalletID string `json:"blsWalletId"`
|
||||
CoronaWalletID string `json:"coronaWalletId"`
|
||||
BLSPublicKey string `json:"blsPublicKey"`
|
||||
BLSPublicKey string `json:"blsPublicKey"`
|
||||
CoronaPublicKey string `json:"coronaPublicKey"`
|
||||
Threshold int `json:"threshold"`
|
||||
Parties int `json:"parties"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Threshold int `json:"threshold"`
|
||||
Parties int `json:"parties"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type kmsGenerateRequest struct {
|
||||
@@ -109,16 +109,16 @@ func (s *Server) handleKMSGenerate(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
now := time.Now().UTC()
|
||||
ks := &ValidatorKeySet{
|
||||
ValidatorID: req.ValidatorID,
|
||||
BLSWalletID: blsResult.WalletID,
|
||||
ValidatorID: req.ValidatorID,
|
||||
BLSWalletID: blsResult.WalletID,
|
||||
CoronaWalletID: coronaResult.WalletID,
|
||||
BLSPublicKey: blsResult.ECDSAPubKey,
|
||||
BLSPublicKey: blsResult.ECDSAPubKey,
|
||||
CoronaPublicKey: coronaResult.EDDSAPubKey,
|
||||
Threshold: req.Threshold,
|
||||
Parties: req.Parties,
|
||||
Status: "active",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Threshold: req.Threshold,
|
||||
Parties: req.Parties,
|
||||
Status: "active",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
if s.db != nil {
|
||||
|
||||
@@ -629,13 +629,13 @@ func (s *Server) handleBiometricEnroll(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
var req struct {
|
||||
CredentialID string `json:"credentialId"`
|
||||
SignedResponse string `json:"signedResponse"`
|
||||
AuthenticatorData string `json:"authenticatorData"`
|
||||
ClientDataJSON string `json:"clientDataJSON"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
Modality string `json:"modality"`
|
||||
LivenessAttestation string `json:"livenessAttestation"` // base64 envelope
|
||||
CredentialID string `json:"credentialId"`
|
||||
SignedResponse string `json:"signedResponse"`
|
||||
AuthenticatorData string `json:"authenticatorData"`
|
||||
ClientDataJSON string `json:"clientDataJSON"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
Modality string `json:"modality"`
|
||||
LivenessAttestation string `json:"livenessAttestation"` // base64 envelope
|
||||
}
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "invalid request body")
|
||||
|
||||
@@ -26,15 +26,15 @@ var errSessionConflict = errors.New("session modified concurrently")
|
||||
|
||||
// sessionResponse is the JSON shape specified in mpc.yaml.
|
||||
type sessionResponse struct {
|
||||
SessionID string `json:"sessionId"`
|
||||
WalletID string `json:"walletId"`
|
||||
GrantedTo string `json:"grantedTo,omitempty"`
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
ValueLimit *string `json:"valueLimit,omitempty"`
|
||||
OperationLimit *int `json:"operationLimit,omitempty"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
SessionID string `json:"sessionId"`
|
||||
WalletID string `json:"walletId"`
|
||||
GrantedTo string `json:"grantedTo,omitempty"`
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
ValueLimit *string `json:"valueLimit,omitempty"`
|
||||
OperationLimit *int `json:"operationLimit,omitempty"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
ExpiresAt time.Time `json:"expiresAt"`
|
||||
RevokedAt *time.Time `json:"revokedAt,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -272,8 +272,8 @@ func (s *Server) handleCreateWalletBackup(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Threshold int `json:"threshold"`
|
||||
TotalShards int `json:"total_shards"`
|
||||
Threshold int `json:"threshold"`
|
||||
TotalShards int `json:"total_shards"`
|
||||
Destinations []string `json:"destinations"`
|
||||
UserWebAuthnPubKey string `json:"user_webauthn_pub_key,omitempty"` // P-256 public key for passkey-encrypted backup
|
||||
}
|
||||
@@ -419,7 +419,7 @@ func (s *Server) handleCreateWalletBackup(w http.ResponseWriter, r *http.Request
|
||||
backup.TotalShards = req.TotalShards
|
||||
backup.Status = "active"
|
||||
backup.UserPasskeyFingerprint = userPasskeyPubKey
|
||||
backup.EncryptedKeyShare = encrypted // AES-256-GCM ciphertext, decryptable ONLY with user's passkey
|
||||
backup.EncryptedKeyShare = encrypted // AES-256-GCM ciphertext, decryptable ONLY with user's passkey
|
||||
backup.EphemeralPublicKey = base64.StdEncoding.EncodeToString(ephPub.Bytes()) // needed for user-side ECDH
|
||||
|
||||
if err := backup.Create(); err != nil {
|
||||
|
||||
@@ -58,16 +58,16 @@ const treasurySignPermission = "mpc.treasury.sign"
|
||||
// --- Request / response shapes ---
|
||||
|
||||
type treasuryWalletResponse struct {
|
||||
WalletID string `json:"walletId"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Chain string `json:"chain"`
|
||||
Signers []treasurySignerView `json:"signers"`
|
||||
Tiers []db.TreasuryTier `json:"tiers"`
|
||||
RegulatorShard bool `json:"regulatorShard"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Outstanding []outstandingOpView `json:"outstanding,omitempty"`
|
||||
WalletID string `json:"walletId"`
|
||||
Name string `json:"name"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Chain string `json:"chain"`
|
||||
Signers []treasurySignerView `json:"signers"`
|
||||
Tiers []db.TreasuryTier `json:"tiers"`
|
||||
RegulatorShard bool `json:"regulatorShard"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Outstanding []outstandingOpView `json:"outstanding,omitempty"`
|
||||
}
|
||||
|
||||
type treasurySignerView struct {
|
||||
|
||||
+36
-35
@@ -78,18 +78,18 @@ type tieredWalletCreateRequest struct {
|
||||
}
|
||||
|
||||
type tieredWalletResponse struct {
|
||||
ID string `json:"id"`
|
||||
OrgID string `json:"orgId"`
|
||||
Tier string `json:"tier"`
|
||||
Chain string `json:"chain"`
|
||||
Address string `json:"address"`
|
||||
GroupPubKey string `json:"groupPubKey,omitempty"` // hex
|
||||
Threshold wallet.ThresholdSpec `json:"threshold"`
|
||||
Nodes []wallet.NodeBinding `json:"nodes"`
|
||||
Policy wallet.TierPolicy `json:"policy"`
|
||||
PolicyID string `json:"policyId,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
ID string `json:"id"`
|
||||
OrgID string `json:"orgId"`
|
||||
Tier string `json:"tier"`
|
||||
Chain string `json:"chain"`
|
||||
Address string `json:"address"`
|
||||
GroupPubKey string `json:"groupPubKey,omitempty"` // hex
|
||||
Threshold wallet.ThresholdSpec `json:"threshold"`
|
||||
Nodes []wallet.NodeBinding `json:"nodes"`
|
||||
Policy wallet.TierPolicy `json:"policy"`
|
||||
PolicyID string `json:"policyId,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
func toTieredWalletResponse(w wallet.Wallet) tieredWalletResponse {
|
||||
@@ -226,16 +226,17 @@ func (s *Server) handleTieredWalletListByTier(w http.ResponseWriter, r *http.Req
|
||||
|
||||
// signDecision represents the outcome of the tier-aware sign dispatch.
|
||||
// Status: "auto_approved" | "approval_required" | "airgapped_queued" |
|
||||
// "timelocked" | "rejected"
|
||||
//
|
||||
// "timelocked" | "rejected"
|
||||
type signDecision struct {
|
||||
Status string `json:"status"`
|
||||
WalletID string `json:"walletId"`
|
||||
Tier string `json:"tier"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
RequiredApprovals int `json:"requiredApprovals,omitempty"`
|
||||
TimelockEndsAt *time.Time `json:"timelockEndsAt,omitempty"`
|
||||
Usage *wallet.UsageView `json:"usage,omitempty"`
|
||||
NextStep string `json:"nextStep,omitempty"`
|
||||
Status string `json:"status"`
|
||||
WalletID string `json:"walletId"`
|
||||
Tier string `json:"tier"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
RequiredApprovals int `json:"requiredApprovals,omitempty"`
|
||||
TimelockEndsAt *time.Time `json:"timelockEndsAt,omitempty"`
|
||||
Usage *wallet.UsageView `json:"usage,omitempty"`
|
||||
NextStep string `json:"nextStep,omitempty"`
|
||||
}
|
||||
|
||||
type tieredSignRequest struct {
|
||||
@@ -250,20 +251,20 @@ type tieredSignRequest struct {
|
||||
//
|
||||
// The decision tree:
|
||||
//
|
||||
// 1. Quarantine: ALWAYS reject. No path to a signature.
|
||||
// 2. Per-tx + daily + velocity limits: enforced first; over-cap rejects.
|
||||
// 3. Airgapped tiers (cold, DR): caller must drive the airgap flow
|
||||
// (pkg/airgap/session). Returns "airgapped_queued" with the next
|
||||
// step. Sibling task #106 finalizes the producer hookup.
|
||||
// 4. Timelocked tiers (cold 24h, contract_admin 48h, DR 7d, quarantine
|
||||
// 72h): returns "timelocked" with TimelockEndsAt; the broadcast
|
||||
// side picks it up after expiry. Sibling task ships the queue.
|
||||
// 5. AutoApproval tiers (hot/gas/bridge/validator): allowlist check +
|
||||
// amount under per-tx limit AND not over the large-amount escalation
|
||||
// threshold → "auto_approved", counters are committed.
|
||||
// 6. Otherwise: requires HumanApprovalsMin (or HumanApprovalsLarge if
|
||||
// amount >= LargeAmount). Returns "approval_required". Sibling task
|
||||
// ships the approval bundle verifier.
|
||||
// 1. Quarantine: ALWAYS reject. No path to a signature.
|
||||
// 2. Per-tx + daily + velocity limits: enforced first; over-cap rejects.
|
||||
// 3. Airgapped tiers (cold, DR): caller must drive the airgap flow
|
||||
// (pkg/airgap/session). Returns "airgapped_queued" with the next
|
||||
// step. Sibling task #106 finalizes the producer hookup.
|
||||
// 4. Timelocked tiers (cold 24h, contract_admin 48h, DR 7d, quarantine
|
||||
// 72h): returns "timelocked" with TimelockEndsAt; the broadcast
|
||||
// side picks it up after expiry. Sibling task ships the queue.
|
||||
// 5. AutoApproval tiers (hot/gas/bridge/validator): allowlist check +
|
||||
// amount under per-tx limit AND not over the large-amount escalation
|
||||
// threshold → "auto_approved", counters are committed.
|
||||
// 6. Otherwise: requires HumanApprovalsMin (or HumanApprovalsLarge if
|
||||
// amount >= LargeAmount). Returns "approval_required". Sibling task
|
||||
// ships the approval bundle verifier.
|
||||
//
|
||||
// KYT and CanonicalIntent verifier interface are referenced via the
|
||||
// sibling LocalVerifier task — for now we surface the requirement in the
|
||||
|
||||
@@ -77,9 +77,9 @@ func TestCrossTenant_OrgIDSanitization(t *testing.T) {
|
||||
input string
|
||||
contains string // must NOT appear in the scoped key
|
||||
}{
|
||||
{"a:b:c", "org:a:b:c:"}, // triple colon injection
|
||||
{"a:b:c", "org:a:b:c:"}, // triple colon injection
|
||||
{"../etc/passwd", "org:../etc/passwd"}, // path traversal (colons don't apply but still test)
|
||||
{"org\x00evil", "org:org\x00evil:"}, // null byte
|
||||
{"org\x00evil", "org:org\x00evil:"}, // null byte
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
@@ -508,4 +508,3 @@ func bytes_repeat(b byte, n int) []byte {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
@@ -72,9 +72,9 @@ func TestBackupShardRequiresPasskey(t *testing.T) {
|
||||
func TestBackupShardRejectsEmptyPasskey(t *testing.T) {
|
||||
// Empty or invalid passkey pubkeys must be rejected.
|
||||
invalidKeys := []string{
|
||||
"", // empty
|
||||
"not-base64!@#$", // garbage
|
||||
base64.StdEncoding.EncodeToString([]byte{0x04}), // too short
|
||||
"", // empty
|
||||
"not-base64!@#$", // garbage
|
||||
base64.StdEncoding.EncodeToString([]byte{0x04}), // too short
|
||||
base64.StdEncoding.EncodeToString(make([]byte, 65)), // starts with 0x00, not 0x04
|
||||
}
|
||||
for _, key := range invalidKeys {
|
||||
|
||||
+10
-10
@@ -68,14 +68,14 @@ type HSMProvider interface {
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
db *db.Database
|
||||
mpc MPCBackend
|
||||
hsm HSMProvider // optional: server-side HSM co-signing
|
||||
tradeApproval *custody.TradeApprovalService
|
||||
txTracker *txtracker.Tracker
|
||||
jwtSecret []byte
|
||||
oidcIssuers []string
|
||||
webauthnRPID string
|
||||
db *db.Database
|
||||
mpc MPCBackend
|
||||
hsm HSMProvider // optional: server-side HSM co-signing
|
||||
tradeApproval *custody.TradeApprovalService
|
||||
txTracker *txtracker.Tracker
|
||||
jwtSecret []byte
|
||||
oidcIssuers []string
|
||||
webauthnRPID string
|
||||
webauthnOrigins map[string]bool
|
||||
// PubKey is the Ed25519 verifying key used to validate
|
||||
// (or any other configured PAD-2 liveness provider) attestations
|
||||
@@ -88,8 +88,8 @@ type Server struct {
|
||||
// intended only for the extended-envelope rollout window.
|
||||
// Configured via MPC_LIVENESS_BINDING=strict|lax (default strict).
|
||||
livenessBindingMode webauthn.BindingMode
|
||||
router chi.Router
|
||||
replayGuard *replayGuard
|
||||
router chi.Router
|
||||
replayGuard *replayGuard
|
||||
|
||||
// approval is the executive-approval registry consumed by /v1/approval/*.
|
||||
// Optional — when nil, those endpoints return 503. Wired via SetApproval.
|
||||
|
||||
@@ -146,7 +146,7 @@ func TestKMSZAP_Auth_RequiredHappyPath(t *testing.T) {
|
||||
|
||||
// Now a sign call should succeed.
|
||||
respOp, signBody := callOp(t, client, peer, OpKMSSign, kmsZapSignRequest{
|
||||
VaultID: "v1", WalletID: "w1", Payload: []byte("x"),
|
||||
VaultID: "v1", WalletID: "w1", Payload: []byte("x"),
|
||||
})
|
||||
if respOp != OpKMSSign {
|
||||
t.Fatalf("sign opcode: got 0x%04x want 0x%04x", respOp, OpKMSSign)
|
||||
@@ -171,7 +171,7 @@ func TestKMSZAP_Auth_RequiredRejectsMissing(t *testing.T) {
|
||||
defer client.Stop()
|
||||
|
||||
op, body := callOp(t, client, peer, OpKMSSign, kmsZapSignRequest{
|
||||
VaultID: "v1", WalletID: "w1", Payload: []byte("x"),
|
||||
VaultID: "v1", WalletID: "w1", Payload: []byte("x"),
|
||||
})
|
||||
if op != OpKMSSign {
|
||||
t.Fatalf("opcode echo: got 0x%04x want 0x%04x", op, OpKMSSign)
|
||||
@@ -204,7 +204,7 @@ func TestKMSZAP_Auth_RequiredRejectsBadToken(t *testing.T) {
|
||||
}
|
||||
|
||||
op, signBody := callOp(t, client, peer, OpKMSSign, kmsZapSignRequest{
|
||||
VaultID: "v1", WalletID: "w1", Payload: []byte("x"),
|
||||
VaultID: "v1", WalletID: "w1", Payload: []byte("x"),
|
||||
})
|
||||
if op != OpKMSSign {
|
||||
t.Fatalf("opcode echo: got 0x%04x want 0x%04x", op, OpKMSSign)
|
||||
@@ -225,7 +225,7 @@ func TestKMSZAP_Auth_AdvisoryAcceptsMissing(t *testing.T) {
|
||||
defer client.Stop()
|
||||
|
||||
op, body := callOp(t, client, peer, OpKMSSign, kmsZapSignRequest{
|
||||
VaultID: "v1", WalletID: "w1", Payload: []byte("x"),
|
||||
VaultID: "v1", WalletID: "w1", Payload: []byte("x"),
|
||||
})
|
||||
if op != OpKMSSign {
|
||||
t.Fatalf("opcode echo: got 0x%04x want 0x%04x", op, OpKMSSign)
|
||||
|
||||
Reference in New Issue
Block a user