package tokenboard // NOTE: This is a sketch implementation, Not suitable for production use. The real auditable store is still being designed. import ( "encoding/json" "git.openprivacy.ca/cwtch.im/tapir" "git.openprivacy.ca/cwtch.im/tapir/applications" "git.openprivacy.ca/cwtch.im/tapir/primitives/auditable" "git.openprivacy.ca/cwtch.im/tapir/primitives/privacypass" "git.openprivacy.ca/openprivacy/log" ) // NewTokenBoardServer generates new Server for Token Board func NewTokenBoardServer(tokenService *privacypass.TokenServer, store *auditable.Store) tapir.Application { tba := new(Server) tba.TokenService = tokenService tba.AuditableStore = store return tba } // Server defines the token board server type Server struct { applications.AuthApp connection tapir.Connection TokenService *privacypass.TokenServer AuditableStore *auditable.Store } // NewInstance creates a new TokenBoardApp func (ta *Server) NewInstance() tapir.Application { tba := new(Server) tba.TokenService = ta.TokenService tba.AuditableStore = ta.AuditableStore return tba } // Init initializes the cryptographic TokenBoardApp func (ta *Server) Init(connection tapir.Connection) { ta.AuthApp.Init(connection) if connection.HasCapability(applications.AuthCapability) { ta.connection = connection go ta.Listen() return } connection.Close() } // Listen processes the messages for this application func (ta *Server) Listen() { for { data := ta.connection.Expect() if len(data) == 0 { return // connection is closed } var message Message json.Unmarshal(data, &message) switch message.MessageType { case postRequestMessage: postrequest := message.PostRequest log.Debugf("Received a Post Message Request: %x %x", postrequest.Token, postrequest.Message) ta.postMessageRequest(postrequest.Token, postrequest.Message) case replayRequestMessage: log.Debugf("Received Replay Request %v", message.ReplayRequest) state := ta.AuditableStore.GetStateAfter(message.ReplayRequest.LastCommit) response, _ := json.Marshal(Message{MessageType: replayResultMessage, ReplayResult: replayResult{len(state.Messages)}}) log.Debugf("Sending Replay Response %v", replayResult{len(state.Messages)}) ta.connection.Send(response) for _, message := range state.Messages { ta.connection.Send(message) } data, _ := json.Marshal(state.SignedProof) ta.connection.Send(data) } } } func (ta *Server) postMessageRequest(token privacypass.SpentToken, message auditable.Message) { if err := ta.TokenService.SpendToken(token, append(message, ta.connection.ID().Hostname()...)); err == nil { log.Debugf("Token is valid") signedproof := ta.AuditableStore.Add(message) data, _ := json.Marshal(Message{MessageType: postResultMessage, PostResult: postResult{true, signedproof}}) ta.connection.Send(data) } else { log.Debugf("Attempt to spend an invalid token: %v", err) data, _ := json.Marshal(Message{MessageType: postResultMessage, PostResult: postResult{false, auditable.SignedProof{}}}) ta.connection.Send(data) } }