siwe

package module
v0.0.0-...-bc128a0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 6, 2022 License: Apache-2.0, MIT Imports: 12 Imported by: 0

README

Sign-In with Ethereum

This package provides a pure Go implementation of EIP-4361: Sign In With Ethereum.

Installation

SIWE can be easily installed in any Go project by running:

go get -u github.com/spruceid/siwe-go

Usage

SIWE exposes a Message struct which implements EIP-4361.

Parsing a SIWE Message

Parsing is done via the siwe.ParseMessage function:

var message *siwe.Message
var err error

message, err = siwe.ParseMessage(messageStr)

The function will return a nil pointer and an error if there was an issue while parsing.

Verifying and Authenticating a SIWE Message

Verification and Authentication is performed via EIP-191, using the address field of the Message as the expected signer. This returns the Ethereum public key of the signer:

var publicKey *ecdsa.PublicKey
var err error

publicKey, err = message.VerifyEIP191(signature)

The time constraints (expiry and not-before) can also be validated, at current or particular times:

var message *siwe.Message

if message.ValidNow() {
  // ...
}

// equivalent to

if message.ValidAt(time.Now().UTC()) {
  // ...
}

Combined verification of time constraints and authentication can be done in a single call with verify:

var publicKey *ecdsa.PublicKey
var err error

// Optional nonce variable to be matched against the
// built message struct being verified
var optionalNonce *string

// Optional timestamp variable to verify at any point
// in time, by default it will use `time.Now()`
var optionalTimestamp *time.Time

publicKey, err = message.Verify(signature, optionalNonce, optionalTimestamp)

// If you won't be using nonce matching and want
// to verify the message at current time, it's
// safe to pass `nil` in both arguments
publicKey, err = message.Verify(signature, nil, nil)
Serialization of a SIWE Message

Message instances can also be serialized as their EIP-4361 string representations via the String method:

fmt.Printf("%s", message.String())

Signing Messages from Go code

To sign messages directly from Go code, you will need to do it like shown below to correctly follow the personal_sign format.

func signHash(data []byte) common.Hash {
	msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
	return crypto.Keccak256Hash([]byte(msg))
}

func signMessage(message string, privateKey *ecdsa.PrivateKey) ([]byte, error) {
	sign := signHash([]byte(message))
	signature, err := crypto.Sign(sign.Bytes(), privateKey)

	if err != nil {
		return nil, err
	}

	signature[64] += 27
	return signature, nil
}

Disclaimer

Our Go library for Sign-In with Ethereum has not yet undergone a formal security audit. We welcome continued feedback on the usability, architecture, and security of this implementation.

See Also

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GenerateNonce

func GenerateNonce() string

Types

type ExpiredMessage

type ExpiredMessage struct {
	// contains filtered or unexported fields
}

func (*ExpiredMessage) Error

func (m *ExpiredMessage) Error() string

type InvalidMessage

type InvalidMessage struct {
	// contains filtered or unexported fields
}

func (*InvalidMessage) Error

func (m *InvalidMessage) Error() string

type InvalidSignature

type InvalidSignature struct {
	// contains filtered or unexported fields
}

func (*InvalidSignature) Error

func (m *InvalidSignature) Error() string

type Message

type Message struct {
	// contains filtered or unexported fields
}

func InitMessage

func InitMessage(domain, address, uri, nonce string, options map[string]interface{}) (*Message, error)

InitMessage creates a Message object with the provided parameters

func ParseMessage

func ParseMessage(message string) (*Message, error)

ParseMessage returns a Message object by parsing an EIP-4361 formatted string

func (*Message) GetAddress

func (m *Message) GetAddress() common.Address

func (*Message) GetChainID

func (m *Message) GetChainID() int

func (*Message) GetDomain

func (m *Message) GetDomain() string

func (*Message) GetExpirationTime

func (m *Message) GetExpirationTime() *string

func (*Message) GetIssuedAt

func (m *Message) GetIssuedAt() string

func (*Message) GetNonce

func (m *Message) GetNonce() string

func (*Message) GetNotBefore

func (m *Message) GetNotBefore() *string

func (*Message) GetRequestID

func (m *Message) GetRequestID() *string

func (*Message) GetResources

func (m *Message) GetResources() []url.URL

func (*Message) GetStatement

func (m *Message) GetStatement() *string

func (*Message) GetURI

func (m *Message) GetURI() url.URL

func (*Message) GetVersion

func (m *Message) GetVersion() string

func (*Message) String

func (m *Message) String() string

func (*Message) ValidAt

func (m *Message) ValidAt(when time.Time) (bool, error)

ValidAt validates the time constraints of the message at a specific point in time.

func (*Message) ValidNow

func (m *Message) ValidNow() (bool, error)

ValidNow validates the time constraints of the message at current time.

func (*Message) Verify

func (m *Message) Verify(signature string, domain *string, nonce *string, timestamp *time.Time) (*ecdsa.PublicKey, error)

Verify validates time constraints and integrity of the object by matching it's signature.

func (*Message) VerifyEIP191

func (m *Message) VerifyEIP191(signature string) (*ecdsa.PublicKey, error)

VerifyEIP191 validates the integrity of the object by matching it's signature.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL