Esempio n. 1
0
// LookupByAddress performs a federated lookup following to the stellar
// federation protocol using the "name" type request.  The provided address is
// used to resolve what server the request should be made against.  NOTE: the
// "name" type is a legacy holdover from the legacy stellar network's federation
// protocol. It is unfortunate.
func (c *Client) LookupByAddress(addy string) (*NameResponse, error) {
	_, domain, err := address.Split(addy)
	if err != nil {
		return nil, errors.Wrap(err, "parse address failed")
	}

	fserv, err := c.getFederationServer(domain)
	if err != nil {
		return nil, errors.Wrap(err, "lookup federation server failed")
	}

	url := c.url(fserv, "name", addy)

	var resp NameResponse
	err = c.getJSON(url, &resp)
	if err != nil {
		return nil, errors.Wrap(err, "get federation failed")
	}

	if resp.MemoType != "" && resp.Memo == "" {
		return nil, errors.New("Invalid federation response (memo)")
	}

	return &resp, nil
}
Esempio n. 2
0
// LookupByAccountID performs a federated lookup following to the stellar
// federation protocol using the "id" type request.  The provided strkey-encoded
// account id is used to resolve what server the request should be made against.
func (c *Client) LookupByAccountID(aid string) (*IDResponse, error) {

	domain, err := c.Horizon.HomeDomainForAccount(aid)
	if err != nil {
		return nil, errors.Wrap(err, "get homedomain failed")
	}

	if domain == "" {
		return nil, errors.New("homedomain not set")
	}

	fserv, err := c.getFederationServer(domain)
	if err != nil {
		return nil, errors.Wrap(err, "lookup federation server failed")
	}

	url := c.url(fserv, "id", aid)

	var resp IDResponse
	err = c.getJSON(url, &resp)
	if err != nil {
		return nil, errors.Wrap(err, "get federation failed")
	}

	return &resp, nil
}
Esempio n. 3
0
func (pl *PaymentListener) postForm(
	url string,
	form url.Values,
) (*http.Response, error) {

	strbody := form.Encode()

	req, err := http.NewRequest("POST", url, strings.NewReader(strbody))
	if err != nil {
		return nil, errors.Wrap(err, "configure http request failed")
	}
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	if pl.config.MACKey != "" {
		rawMAC, err := pl.getMAC(pl.config.MACKey, []byte(strbody))
		if err != nil {
			return nil, errors.Wrap(err, "getMAC failed")
		}

		encMAC := base64.StdEncoding.EncodeToString(rawMAC)
		req.Header.Set("X_PAYLOAD_MAC", encMAC)
	}

	resp, err := pl.client.Do(req)
	if err != nil {
		return nil, errors.Wrap(err, "http request errored")
	}

	return resp, nil
}
Esempio n. 4
0
func initDriver(cfg Config) (federation.Driver, error) {
	var dialect string

	switch cfg.Database.Type {
	case "mysql":
		dialect = "mysql"
	case "postgres":
		dialect = "postgres"
	case "sqlite3":
		dialect = "sqlite3"
	default:
		return nil, errors.Errorf("Invalid db type: %s", cfg.Database.Type)
	}

	repo, err := db.Open(dialect, cfg.Database.URL)
	if err != nil {
		return nil, errors.Wrap(err, "db open failed")
	}

	sqld := federation.SQLDriver{
		DB:                repo.DB.DB, // unwrap the repo to the bare *sql.DB instance,
		LookupRecordQuery: cfg.Queries.Federation,
	}

	if cfg.Queries.ReverseFederation == "" {
		return &sqld, nil
	}

	rsqld := federation.ReverseSQLDriver{
		SQLDriver:                sqld,
		LookupReverseRecordQuery: cfg.Queries.ReverseFederation,
	}

	return &rsqld, nil
}
Esempio n. 5
0
// Run starts an http server using the provided config struct.
//
// This method configures the process to listen for termination signals (SIGINT
// and SIGTERM) to trigger a graceful shutdown by way of the graceful package
// (https://github.com/tylerb/graceful).
func Run(conf Config) {
	srv := setup(conf)

	http2.ConfigureServer(srv.Server, nil)

	if conf.OnStarting != nil {
		conf.OnStarting()
	}

	var err error
	if conf.TLSCert != "" {
		err = srv.ListenAndServeTLS(conf.TLSCert, conf.TLSKey)
	} else {
		err = srv.ListenAndServe()
	}

	if err != nil {
		log.Error(errors.Wrap(err, "failed to start server"))
		os.Exit(1)
	}

	if conf.OnStopped != nil {
		conf.OnStopped()
	}
	os.Exit(0)
}
Esempio n. 6
0
// package searches the `tools` and `services` packages of this repo to find
// the source directory.  This is used within the script to find the README and
// other files that should be packaged with the binary.
func packageName(binName string) string {
	targets := []string{
		filepath.Join("services", binName),
		filepath.Join("tools", binName),
	}

	var result string

	// Note: we do not short circuit this search when we find a valid result so
	// that we can panic when multiple results are found.  The children of
	// /services and /tools should not have name overlap.
	for _, t := range targets {
		_, err := os.Stat(t)

		if os.IsNotExist(err) {
			continue
		}

		if err != nil {
			panic(errors.Wrap(err, "stat failed"))
		}

		if result != "" {
			panic("sourceDir() found multiple results!")
		}

		result = t
	}

	return result
}
Esempio n. 7
0
// GetStellarTomlByAddress returns stellar.toml file of a domain fetched from a
// given address
func (c *Client) GetStellarTomlByAddress(addy string) (*Response, error) {
	_, domain, err := address.Split(addy)
	if err != nil {
		return nil, errors.Wrap(err, "parse address failed")
	}

	return c.GetStellarToml(domain)
}
Esempio n. 8
0
// build converts the provided sql builder `b` into the sql and args to execute
// against the raw database connections.
func (r *Repo) build(b sq.Sqlizer) (sql string, args []interface{}, err error) {
	sql, args, err = b.ToSql()

	if err != nil {
		err = errors.Wrap(err, "to-sql failed")
	}
	return
}
Esempio n. 9
0
// Open the postgres database at `url` and returns a new *Repo using it.
func Open(dialect, url string) (*Repo, error) {
	db, err := sqlx.Connect(dialect, url)
	if err != nil {
		return nil, errors.Wrap(err, "connect failed")
	}

	return &Repo{DB: db}, nil
}
Esempio n. 10
0
// pushdir is a utility function to temporarily change directories.  It returns
// a func that can be called to restore the current working directory to the
// state it was in when first calling pushdir.
func pushdir(dir string) func() {
	cwd, err := os.Getwd()
	if err != nil {
		panic(errors.Wrap(err, "getwd failed"))
	}

	err = os.Chdir(dir)
	if err != nil {
		panic(errors.Wrap(err, "chdir failed"))
	}

	return func() {
		err := os.Chdir(cwd)
		if err != nil {
			panic(errors.Wrap(err, "revert dir failed"))
		}
	}
}
Esempio n. 11
0
// getJSON populates `dest` with the contents at `url`, provided the request
// succeeds and the json can be successfully decoded.
func (c *Client) getJSON(url string, dest interface{}) error {
	hresp, err := c.HTTP.Get(url)
	if err != nil {
		return errors.Wrap(err, "http get errored")
	}

	defer hresp.Body.Close()

	if !(hresp.StatusCode >= 200 && hresp.StatusCode < 300) {
		return errors.Errorf("http get failed with (%d) status code", hresp.StatusCode)
	}

	err = json.NewDecoder(hresp.Body).Decode(dest)
	if err != nil {
		return errors.Wrap(err, "json decode errored")
	}

	return nil
}
Esempio n. 12
0
func (pl *PaymentListener) getMAC(key string, raw []byte) ([]byte, error) {

	rawkey, err := strkey.Decode(strkey.VersionByteSeed, pl.config.MACKey)
	if err != nil {
		return nil, errors.Wrap(err, "invalid MAC key")
	}

	macer := hmac.New(sha256.New, rawkey)
	macer.Write(raw)
	return macer.Sum(nil), nil
}
Esempio n. 13
0
// HashTransaction derives the network specific hash for the provided
// transaction using the network identified by the supplied passphrase.  The
// resulting hash is the value that can be signed by stellar secret key to
// authorize the transaction identified by the hash to stellar validators.
func HashTransaction(tx *xdr.Transaction, passphrase string) ([32]byte, error) {
	var txBytes bytes.Buffer

	_, err := fmt.Fprintf(&txBytes, "%s", ID(passphrase))
	if err != nil {
		return [32]byte{}, errors.Wrap(err, "fprint network id failed")
	}

	_, err = xdr.Marshal(&txBytes, xdr.EnvelopeTypeEnvelopeTypeTx)
	if err != nil {
		return [32]byte{}, errors.Wrap(err, "marshal type failed")
	}

	_, err = xdr.Marshal(&txBytes, tx)
	if err != nil {
		return [32]byte{}, errors.Wrap(err, "marshal tx failed")
	}

	return hash.Hash(txBytes.Bytes()), nil
}
Esempio n. 14
0
// Envelope extracts the transaction envelope that triggered this error from the
// extra fields.
func (herr *Error) Envelope() (*xdr.TransactionEnvelope, error) {
	raw, ok := herr.Problem.Extras["envelope_xdr"]
	if !ok {
		return nil, ErrEnvelopeNotPopulated
	}

	var b64 string
	var result xdr.TransactionEnvelope

	err := json.Unmarshal(raw, &b64)
	if err != nil {
		return nil, errors.Wrap(err, "json decode failed")
	}

	err = xdr.SafeUnmarshalBase64(b64, &result)
	if err != nil {
		return nil, errors.Wrap(err, "xdr decode failed")
	}

	return &result, nil
}
Esempio n. 15
0
// BuildTime returns the time that the binary of the current process was built.
// Our build script populates the `buildTime` var used to provide this result.
func BuildTime() (time.Time, error) {
	if buildTime == "" {
		return time.Time{}, ErrNoBuildTime
	}

	t, err := time.Parse(time.RFC3339, buildTime)
	if err != nil {
		return time.Time{}, errors.Wrap(err, "parse failed")
	}

	return t, nil
}
Esempio n. 16
0
// randomName returns a new psuedo-random name that is sufficient for naming a
// test database.  In the event that reading from the source of randomness
// fails, a panic will occur.
func randomName() string {
	raw := make([]byte, 6)

	_, err := rand.Read(raw)
	if err != nil {
		err = errors.Wrap(err, "read from rand failed")
		panic(err)
	}

	enc := hex.EncodeToString(raw)

	return fmt.Sprintf("test_%s", enc)
}
Esempio n. 17
0
// GetStellarToml returns stellar.toml file for a given domain
func (c *Client) GetStellarToml(domain string) (resp *Response, err error) {
	var hresp *http.Response
	hresp, err = c.HTTP.Get(c.url(domain))
	if err != nil {
		err = errors.Wrap(err, "http request errored")
		return
	}
	defer hresp.Body.Close()

	if !(hresp.StatusCode >= 200 && hresp.StatusCode < 300) {
		err = errors.New("http request failed with non-200 status code")
		return
	}

	_, err = toml.DecodeReader(hresp.Body, &resp)
	if err != nil {
		err = errors.Wrap(err, "toml decode failed")
		return
	}

	return
}
Esempio n. 18
0
// Begin binds this repo to a new transaction.
func (r *Repo) Begin() error {
	if r.tx != nil {
		return errors.New("already in transaction")
	}

	tx, err := r.DB.Beginx()
	if err != nil {
		return errors.Wrap(err, "beginx failed")
	}
	r.logBegin()

	r.tx = tx
	return nil
}
Esempio n. 19
0
// Postgres provisions a new, blank database with a random name on the localhost
// of the running process.  It assumes that you have postgres running on the
// default port, have the command line postgres tools installed, and that the
// current user has access to the server.  It panics on the event of a failure.
func Postgres() *DB {
	var result DB
	name := randomName()
	result.Dialect = "postgres"
	result.DSN = fmt.Sprintf("postgres://localhost/%s?sslmode=disable", name)

	// create the db
	err := exec.Command("createdb", name).Run()
	if err != nil {
		err = errors.Wrap(err, "createdb failed")
		panic(err)
	}

	result.closer = func() {
		err := exec.Command("dropdb", name).Run()
		if err != nil {
			err = errors.Wrap(err, "dropdb failed")
			panic(err)
		}
	}

	return &result
}
Esempio n. 20
0
// Mysql provisions a new, blank database with a random name on the localhost of
// the running process.  It assumes that you have mysql running and that the
// root user has access with no password.  It panics on
// the event of a failure.
func Mysql() *DB {
	var result DB
	name := randomName()
	result.Dialect = "mysql"
	result.DSN = fmt.Sprintf("root@/%s", name)

	// create the db
	err := exec.Command("mysql", "-e", fmt.Sprintf("CREATE DATABASE %s;", name)).Run()
	if err != nil {
		err = errors.Wrap(err, "createdb failed")
		panic(err)
	}

	result.closer = func() {
		err := exec.Command("mysql", "-e", fmt.Sprintf("DROP DATABASE %s;", name)).Run()
		if err != nil {
			err = errors.Wrap(err, "dropdb failed")
			panic(err)
		}
	}

	return &result
}
Esempio n. 21
0
// LookupRecord implements `Driver` by performing `drv.LookupRecordQuery`
// against `drv.DB` using the provided parameters
func (drv *SQLDriver) LookupRecord(name, domain string) (*Record, error) {
	drv.initDB()
	var result Record

	err := drv.db.GetRaw(&result, drv.LookupRecordQuery, name, domain)

	if drv.db.NoRows(err) {
		return nil, nil
	} else if err != nil {
		return nil, errors.Wrap(err, "db get")
	}

	return &result, nil
}
Esempio n. 22
0
// LookupReverseRecord implements `ReverseDriver` by performing
// `drv.LookupReverseRecordQuery` against `drv.DB` using the provided parameter
func (drv *ReverseSQLDriver) LookupReverseRecord(
	accountid string,
) (*ReverseRecord, error) {
	drv.initDB()
	var result ReverseRecord

	err := drv.db.GetRaw(&result, drv.LookupReverseRecordQuery, accountid)

	if drv.db.NoRows(err) {
		return nil, nil
	} else if err != nil {
		return nil, errors.Wrap(err, "db get")
	}

	return &result, nil
}
Esempio n. 23
0
// ExecRaw runs `query` with `args`
func (r *Repo) ExecRaw(query string, args ...interface{}) (sql.Result, error) {
	query = r.conn().Rebind(query)
	start := time.Now()
	result, err := r.conn().Exec(query, args...)
	r.log("exec", start, query, args)

	if err == nil {
		return result, nil
	}

	if r.NoRows(err) {
		return nil, err
	}

	return nil, errors.Wrap(err, "exec failed")
}
Esempio n. 24
0
// QueryRaw runs `query` with `args`
func (r *Repo) QueryRaw(query string, args ...interface{}) (*sqlx.Rows, error) {
	query = r.conn().Rebind(query)
	start := time.Now()
	result, err := r.conn().Queryx(query, args...)
	r.log("query", start, query, args)

	if err == nil {
		return result, nil
	}

	if r.NoRows(err) {
		return nil, err
	}

	return nil, errors.Wrap(err, "query failed")
}
Esempio n. 25
0
// GetRaw runs `query` with `args`, setting the first result found on
// `dest`, if any.
func (r *Repo) GetRaw(dest interface{}, query string, args ...interface{}) error {
	query = r.conn().Rebind(query)
	start := time.Now()
	err := r.conn().Get(dest, query, args...)
	r.log("get", start, query, args)

	if err == nil {
		return nil
	}

	if r.NoRows(err) {
		return err
	}

	return errors.Wrap(err, "get failed")
}
Esempio n. 26
0
func (c *Client) getFederationServer(domain string) (string, error) {
	stoml, err := c.StellarTOML.GetStellarToml(domain)
	if err != nil {
		return "", errors.Wrap(err, "get stellar.toml failed")
	}

	if stoml.FederationServer == "" {
		return "", errors.New("stellar.toml is missing federation server info")
	}

	if !c.AllowHTTP && !strings.HasPrefix(stoml.FederationServer, "https://") {
		return "", errors.New("non-https federation server disallowed")
	}

	return stoml.FederationServer, nil
}
Esempio n. 27
0
// Read takes the TOML configuration file at `path`, parses it into `dest` and
// then uses github.com/asaskevich/govalidator to validate the struct.
func Read(path string, dest interface{}) error {
	_, err := toml.DecodeFile(path, dest)
	if err != nil {
		return errors.Wrap(err, "decode-file failed")
	}

	valid, err := govalidator.ValidateStruct(dest)

	if valid {
		return nil
	}

	fields := govalidator.ErrorsByField(err)

	return &InvalidConfigError{
		InvalidFields: fields,
	}
}
Esempio n. 28
0
// ResultCodes extracts a result code summary from the error, if possible.
func (herr *Error) ResultCodes() (*TransactionResultCodes, error) {
	if herr.Problem.Type != "transaction_failed" {
		return nil, ErrTransactionNotFailed
	}

	raw, ok := herr.Problem.Extras["result_codes"]
	if !ok {
		return nil, ErrResultCodesNotPopulated
	}

	var result TransactionResultCodes
	err := json.Unmarshal(raw, &result)
	if err != nil {
		return nil, errors.Wrap(err, "json decode failed")
	}

	return &result, nil
}
Esempio n. 29
0
// SelectRaw runs `query` with `args`, setting the results found on `dest`.
func (r *Repo) SelectRaw(
	dest interface{},
	query string,
	args ...interface{},
) error {
	r.clearSliceIfPossible(dest)
	query = r.conn().Rebind(query)
	start := time.Now()
	err := r.conn().Select(dest, query, args...)
	r.log("select", start, query, args)

	if err == nil {
		return nil
	}

	if r.NoRows(err) {
		return err
	}

	return errors.Wrap(err, "select failed")
}