Newer
Older
////////////////////////////////////////////////////////////////////////////////
// //
// Use of this source code is governed by a license that can be found in the //
////////////////////////////////////////////////////////////////////////////////
//go:build js && wasm
package wasm
import (

Richard T. Carback III
committed
"gitlab.com/elixxir/client/v4/bindings"
"gitlab.com/elixxir/wasm-utils/exception"
"gitlab.com/elixxir/wasm-utils/utils"
"syscall/js"
)
////////////////////////////////////////////////////////////////////////////////
// Structs and Interfaces //
////////////////////////////////////////////////////////////////////////////////
// UserDiscovery wraps the [bindings.UserDiscovery] object so its methods can be
// wrapped to be Javascript compatible.
type UserDiscovery struct {
api *bindings.UserDiscovery
}
// newE2eJS creates a new Javascript compatible object (map[string]any) that
// matches the [E2e] structure.
func newUserDiscoveryJS(api *bindings.UserDiscovery) map[string]any {
"GetID": js.FuncOf(ud.GetID),
"GetFacts": js.FuncOf(ud.GetFacts),
"GetContact": js.FuncOf(ud.GetContact),
"ConfirmFact": js.FuncOf(ud.ConfirmFact),
"SendRegisterFact": js.FuncOf(ud.SendRegisterFact),
"PermanentDeleteAccount": js.FuncOf(ud.PermanentDeleteAccount),
"RemoveFact": js.FuncOf(ud.RemoveFact),
}
return udMap
}
// GetID returns the ID for this [UserDiscovery] in the [UserDiscovery] tracker.
// - Tracker ID (int).
func (ud *UserDiscovery) GetID(js.Value, []js.Value) any {
return ud.api.GetID()
}
// udNetworkStatus wraps Javascript callbacks to adhere to the
// [bindings.UdNetworkStatus] interface.
type udNetworkStatus struct {
// UdNetworkStatus returns the status of UD.
//
// Returns:
func (uns *udNetworkStatus) UdNetworkStatus() int {
return uns.udNetworkStatus().Int()
}
////////////////////////////////////////////////////////////////////////////////
// Manager functions //
////////////////////////////////////////////////////////////////////////////////
// NewOrLoadUd loads an existing Manager from storage or creates a new one if
// there is no extant storage information. Parameters need be provided to
// specify how to connect to the User Discovery service. These parameters may be
// used to contact either the UD server hosted by the xx network team or a
// custom third-party operated server. For the former, all the information may
// be pulled from the NDF using the bindings.
//
// Params
// - args[0] - ID of [E2e] object in tracker (int).
// - args[1] - Javascript object that has functions that implement the
// [bindings.UdNetworkStatus] interface. This is the network follower
// function wrapped in [bindings.UdNetworkStatus].
// - args[2] - The username the user wants to register with UD. If the user is
// already registered, this field may be blank (string).
// - args[3] - The registration validation signature; a signature provided by
// the network (i.e., the client registrar). This may be nil; however, UD
// may return an error in some cases (e.g., in a production level
// environment) (Uint8Array).
// - args[4] - The TLS certificate for the UD server this call will connect
// with. You may use the UD server run by the xx network team by using
// [E2e.GetUdCertFromNdf] (Uint8Array).
// - args[5] - Marshalled bytes of the [contact.Contact] of the server this
// call will connect with. You may use the UD server run by the xx network
// team by using [E2e.GetUdContactFromNdf] (Uint8Array).
// - args[6] - the IP address of the UD server this call will connect with.
// You may use the UD server run by the xx network team by using
// [E2e.GetUdAddressFromNdf] (string).
// - Javascript representation of the [UserDiscovery] object that is
// registered to the specified UD service.
func NewOrLoadUd(_ js.Value, args []js.Value) any {
follower := &udNetworkStatus{utils.WrapCB(args[1], "UdNetworkStatus")}
registrationValidationSignature := utils.CopyBytesToGo(args[3])
cert := utils.CopyBytesToGo(args[4])
contactFile := utils.CopyBytesToGo(args[5])
address := args[6].String()
api, err := bindings.NewOrLoadUd(e2eID, follower, username,
registrationValidationSignature, cert, contactFile, address)
if err != nil {
return nil
}
return newUserDiscoveryJS(api)
}
// NewUdManagerFromBackup builds a new user discover manager from a backup. It
// will construct a manager that is already registered and restore already
// registered facts into store.
//
// Note that it can take in both ane email address and a phone number or both.
// However, at least one fact must be specified; providing no facts will return
// an error.
//
// Parameters:
// - args[0] - ID of [E2e] object in tracker (int).
// - args[1] - Javascript object that has functions that implement the
// [bindings.UdNetworkStatus] interface. This is the network follower
// function wrapped in [bindings.UdNetworkStatus].
// - args[2] - The TLS certificate for the UD server this call will connect
// with. You may use the UD server run by the xx network team by using
// [E2e.GetUdCertFromNdf] (Uint8Array).
// - args[3] - Marshalled bytes of the [contact.Contact] of the server this
// call will connect with. You may use the UD server run by the xx network
// team by using [E2e.GetUdContactFromNdf] (Uint8Array).
// - args[4] - The IP address of the UD server this call will connect with.
// You may use the UD server run by the xx network team by using
// [E2e.GetUdAddressFromNdf] (string).
// - Javascript representation of the [UserDiscovery] object that is loaded
// from backup.
// - Throws an error if getting UD from backup fails.
func NewUdManagerFromBackup(_ js.Value, args []js.Value) any {
follower := &udNetworkStatus{utils.WrapCB(args[1], "UdNetworkStatus")}
cert := utils.CopyBytesToGo(args[5])
contactFile := utils.CopyBytesToGo(args[6])
address := args[7].String()
return nil
}
return newUserDiscoveryJS(api)
}
// GetFacts returns a JSON marshalled list of [fact.Fact] objects that exist
// within the Store's registeredFacts map.
//
// Returns:
// - JSON of [fact.FactList] (Uint8Array).
func (ud *UserDiscovery) GetFacts(js.Value, []js.Value) any {
}
// GetContact returns the marshalled bytes of the [contact.Contact] for UD as
// retrieved from the NDF.
//
// Returns:
// - Marshalled bytes of [contact.Contact] (Uint8Array).
// - Throws TypeError if getting the contact fails.
func (ud *UserDiscovery) GetContact(js.Value, []js.Value) any {
// ConfirmFact confirms a fact first registered via
// [UserDiscovery.SendRegisterFact]. The confirmation ID comes from
// [UserDiscovery.SendRegisterFact] while the code will come over the associated
// communications system.
// - args[0] - Confirmation ID (string).
// - args[1] - Code (string).
// - Throws TypeError if confirming the fact fails.
func (ud *UserDiscovery) ConfirmFact(_ js.Value, args []js.Value) any {
err := ud.api.ConfirmFact(args[0].String(), args[1].String())
if err != nil {
return nil
}
return nil
}
// SendRegisterFact adds a fact for the user to user discovery. Will only
// succeed if the user is already registered and the system does not have the
// fact currently registered for any user.
//
// This does not complete the fact registration process, it returns a
// confirmation ID instead. Over the communications system the fact is
// associated with, a code will be sent. This confirmation ID needs to be called
// along with the code to finalize the fact.
//
// Parameters:
// - args[0] - JSON of [fact.Fact] (Uint8Array).
// - The confirmation ID (string).
// - Throws TypeError if sending the fact fails.
func (ud *UserDiscovery) SendRegisterFact(_ js.Value, args []js.Value) any {
confirmationID, err := ud.api.SendRegisterFact(utils.CopyBytesToGo(args[0]))
return nil
}
return confirmationID
}
// PermanentDeleteAccount removes the username associated with this user from
// the UD service. This will only take a username type fact, and the fact must
// be associated with this user.
//
// Parameters:
// - args[0] - JSON of [fact.Fact] (Uint8Array).
// - Throws TypeError if deletion fails.
func (ud *UserDiscovery) PermanentDeleteAccount(_ js.Value, args []js.Value) any {
err := ud.api.PermanentDeleteAccount(utils.CopyBytesToGo(args[0]))
return nil
}
return nil
}
// RemoveFact removes a previously confirmed fact. This will fail if the fact
// passed in is not UD service does not associate this fact with this user.
//
// Parameters:
// - args[0] - JSON of [fact.Fact] (Uint8Array).
// - Throws TypeError if removing the fact fails.
func (ud *UserDiscovery) RemoveFact(_ js.Value, args []js.Value) any {
err := ud.api.RemoveFact(utils.CopyBytesToGo(args[0]))
return nil
}
return nil
}
////////////////////////////////////////////////////////////////////////////////
// User Discovery Lookup //
////////////////////////////////////////////////////////////////////////////////
// udLookupCallback wraps Javascript callbacks to adhere to the
// [bindings.UdLookupCallback] interface.
type udLookupCallback struct {
// Callback is called by [LookupUD] to return the contact that matches the
// passed in ID.
// - contactBytes - Marshalled bytes of the [contact.Contact] returned from
// the lookup, or nil if an error occurs (Uint8Array).
// - err - Returns an error on failure (Error).
func (ulc *udLookupCallback) Callback(contactBytes []byte, err error) {
ulc.callback(utils.CopyBytesToJS(contactBytes), exception.NewTrace(err))
}
// LookupUD returns the public key of the passed ID as known by the user
// discovery system or returns by the timeout.
//
// Parameters:
// - args[0] - ID of [E2e] object in tracker (int).
// - args[1] - Marshalled bytes of the User Discovery's [contact.Contact]
// (Uint8Array).
// - args[2] - Javascript object that has functions that implement the
// [bindings.UdLookupCallback] interface.
// - args[3] - Marshalled bytes of the [id.ID] for the user to look up
// (Uint8Array).
// - args[4] - JSON of [single.RequestParams] (Uint8Array).
// - Resolves to the JSON of the [bindings.SingleUseSendReport], which can be
// passed into [Cmix.WaitForRoundResult] to see if the send succeeded
// (Uint8Array).
// - Rejected with an error if the lookup fails.
func LookupUD(_ js.Value, args []js.Value) any {
udContact := utils.CopyBytesToGo(args[1])
cb := &udLookupCallback{utils.WrapCB(args[2], "Callback")}
lookupId := utils.CopyBytesToGo(args[3])
singleRequestParamsJSON := utils.CopyBytesToGo(args[4])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
sendReport, err := bindings.LookupUD(
e2eID, udContact, cb, lookupId, singleRequestParamsJSON)
if err != nil {
} else {
resolve(utils.CopyBytesToJS(sendReport))
}
}
////////////////////////////////////////////////////////////////////////////////
// User Discovery Search //
////////////////////////////////////////////////////////////////////////////////
// udSearchCallback wraps Javascript callbacks to adhere to the
// [bindings.UdSearchCallback] interface.
type udSearchCallback struct {
// Callback is called by [SearchUD] to return a list of [contact.Contact]
// objects that match the list of facts passed into [SearchUD].
// - contactListJSON - JSON of an array of [contact.Contact], or nil if an
// error occurs (Uint8Array).
// - err - Returns any error that occurred in the search (Error).
//
// {
// "<xxc(2)F8dL9EC6gy+RMJuk3R+Au6eGExo02Wfio5cacjBcJRwDEgB7Ugdw/BAr6RkCABkWAFV1c2VybmFtZTA7c4LzV05sG+DMt+rFB0NIJg==xxc>",
// "<xxc(2)eMhAi/pYkW5jCmvKE5ZaTglQb+fTo1D8NxVitr5CCFADEgB7Ugdw/BAr6RoCABkWAFV1c2VybmFtZTE7fElAa7z3IcrYrrkwNjMS2w==xxc>",
// "<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>"
// }
func (usc *udSearchCallback) Callback(contactListJSON []byte, err error) {
usc.callback(utils.CopyBytesToJS(contactListJSON), exception.NewTrace(err))
}
// SearchUD searches user discovery for the passed Facts. The searchCallback
// will return a list of contacts, each having the facts it hit against. This is
// NOT intended to be used to search for multiple users at once; that can have a
// privacy reduction. Instead, it is intended to be used to search for a user
// where multiple pieces of information is known.
//
// Parameters:
// - args[0] - ID of [E2e] object in tracker (int).
// - args[1] - Marshalled bytes of the User Discovery's [contact.Contact]
// (Uint8Array).
// - args[2] - JSON of [fact.FactList] (Uint8Array).
// - args[4] - JSON of [single.RequestParams] (Uint8Array).
// - Resolves to the JSON of the [bindings.SingleUseSendReport], which can be
// passed into [Cmix.WaitForRoundResult] to see if the send succeeded
// (Uint8Array).
// - Rejected with an error if the search fails.
func SearchUD(_ js.Value, args []js.Value) any {
udContact := utils.CopyBytesToGo(args[1])
cb := &udSearchCallback{utils.WrapCB(args[2], "Callback")}
factListJSON := utils.CopyBytesToGo(args[3])
singleRequestParamsJSON := utils.CopyBytesToGo(args[4])
promiseFn := func(resolve, reject func(args ...any) js.Value) {
sendReport, err := bindings.SearchUD(
e2eID, udContact, cb, factListJSON, singleRequestParamsJSON)
if err != nil {
} else {
resolve(utils.CopyBytesToJS(sendReport))
}