func (s *Account) UpdatePassword(ctx context.Context, req *account.UpdatePasswordRequest, rsp *account.UpdatePasswordResponse) error { usr, err := db.Read(req.UserId) if err != nil { return errors.InternalServerError("go.micro.srv.user.updatepassword", err.Error()) } salt, hashed, err := db.SaltAndPassword(usr.Username, usr.Email) if err != nil { return errors.InternalServerError("go.micro.srv.user.updatepassword", err.Error()) } hh, err := base64.StdEncoding.DecodeString(hashed) if err != nil { return errors.InternalServerError("go.micro.srv.user.updatepassword", err.Error()) } if err := bcrypt.CompareHashAndPassword(hh, []byte(x+salt+req.OldPassword)); err != nil { return errors.Unauthorized("go.micro.srv.user.updatepassword", err.Error()) } salt = random(16) h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.NewPassword), 10) if err != nil { return errors.InternalServerError("go.micro.srv.user.updatepassword", err.Error()) } pp := base64.StdEncoding.EncodeToString(h) if err := db.UpdatePassword(req.UserId, salt, pp); err != nil { return errors.InternalServerError("go.micro.srv.user.updatepassword", err.Error()) } return nil }
func (s *Account) Create(ctx context.Context, req *account.CreateRequest, rsp *account.CreateResponse) error { // validate incoming if err := validateAccount(req.Account, "Create"); err != nil { return err } // set a uuid if we dont have one if len(req.Account.Id) == 0 { req.Account.Id = uuid.NewUUID().String() } // hash the pass salt := db.Salt() h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.Account.ClientSecret), 10) if err != nil { return errors.InternalServerError("go.micro.srv.auth.Create", err.Error()) } pp := base64.StdEncoding.EncodeToString(h) // to lower req.Account.ClientId = strings.ToLower(req.Account.ClientId) req.Account.Type = strings.ToLower(req.Account.Type) if err := db.Create(req.Account, salt, pp); err != nil { return errors.InternalServerError("go.micro.srv.auth.Create", err.Error()) } return nil }
func (g *grpcClient) Publish(ctx context.Context, p client.Publication, opts ...client.PublishOption) error { md, ok := metadata.FromContext(ctx) if !ok { md = make(map[string]string) } md["Content-Type"] = p.ContentType() cf, err := g.newCodec(p.ContentType()) if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } b := &buffer{bytes.NewBuffer(nil)} if err := cf(b).Write(&codec.Message{Type: codec.Publication}, p.Message()); err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } g.once.Do(func() { g.opts.Broker.Connect() }) return g.opts.Broker.Publish(p.Topic(), &broker.Message{ Header: md, Body: b.Bytes(), }) }
func (s *Account) Login(ctx context.Context, req *account.LoginRequest, rsp *account.LoginResponse) error { username := strings.ToLower(req.Username) email := strings.ToLower(req.Email) salt, hashed, err := db.SaltAndPassword(username, email) if err != nil { return err } hh, err := base64.StdEncoding.DecodeString(hashed) if err != nil { return errors.InternalServerError("go.micro.srv.user.Login", err.Error()) } if err := bcrypt.CompareHashAndPassword(hh, []byte(x+salt+req.Password)); err != nil { return errors.Unauthorized("go.micro.srv.user.login", err.Error()) } // save session sess := &account.Session{ Id: random(128), Username: username, Created: time.Now().Unix(), Expires: time.Now().Add(time.Hour * 24 * 7).Unix(), } if err := db.CreateSession(sess); err != nil { return errors.InternalServerError("go.micro.srv.user.Login", err.Error()) } rsp.Session = sess return nil }
func authClient(clientId, clientSecret string) error { acc, err := db.Search(clientId, "", 1, 0) if err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } if len(acc) == 0 { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } // check the secret salt, secret, err := db.SaltAndSecret(acc[0].Id) if err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } s, err := base64.StdEncoding.DecodeString(secret) if err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } // does it match? if err := bcrypt.CompareHashAndPassword(s, []byte(x+salt+clientSecret)); err != nil { return errors.BadRequest("go.micro.srv.auth", "access_denied") } return nil }
func (o *Oauth2) Revoke(ctx context.Context, req *oauth2.RevokeRequest, rsp *oauth2.RevokeResponse) error { // Who should be allowed to do this? if len(req.RefreshToken) > 0 { token, _, err := db.ReadRefresh(req.RefreshToken) if err != nil { if err == db.ErrNotFound { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } return errors.InternalServerError("go.micro.srv.auth", "server_error") } if err := db.DeleteToken(req.AccessToken); err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } req.AccessToken = token.AccessToken } if len(req.AccessToken) == 0 { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } if err := db.DeleteToken(req.AccessToken); err != nil { return errors.InternalServerError("go.micro.srv.auth", "server_error") } return nil }
func (r *rpcClient) stream(ctx context.Context, address string, req Request, opts CallOptions) (Streamer, error) { msg := &transport.Message{ Header: make(map[string]string), } md, ok := metadata.FromContext(ctx) if ok { for k, v := range md { msg.Header[k] = v } } // set timeout in nanoseconds msg.Header["Timeout"] = fmt.Sprintf("%d", opts.RequestTimeout) // set the content type for the request msg.Header["Content-Type"] = req.ContentType() cf, err := r.newCodec(req.ContentType()) if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } c, err := r.opts.Transport.Dial(address, transport.WithStream(), transport.WithTimeout(opts.DialTimeout)) if err != nil { return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) } stream := &rpcStream{ context: ctx, request: req, closed: make(chan bool), codec: newRpcPlusCodec(msg, c, cf), } ch := make(chan error, 1) go func() { ch <- stream.Send(req.Request()) }() var grr error select { case err := <-ch: grr = err case <-ctx.Done(): grr = errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408) } if grr != nil { stream.Close() return nil, grr } return stream, nil }
func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) { if req.Method != "POST" { err := errors.BadRequest("go.micro.broker", "Method not allowed") http.Error(w, err.Error(), http.StatusMethodNotAllowed) return } defer req.Body.Close() req.ParseForm() b, err := ioutil.ReadAll(req.Body) if err != nil { errr := errors.InternalServerError("go.micro.broker", fmt.Sprintf("Error reading request body: %v", err)) w.WriteHeader(500) w.Write([]byte(errr.Error())) return } var m *Message if err = json.Unmarshal(b, &m); err != nil { errr := errors.InternalServerError("go.micro.broker", fmt.Sprintf("Error parsing request body: %v", err)) w.WriteHeader(500) w.Write([]byte(errr.Error())) return } topic := m.Header[":topic"] delete(m.Header, ":topic") if len(topic) == 0 { errr := errors.InternalServerError("go.micro.broker", "Topic not found") w.WriteHeader(500) w.Write([]byte(errr.Error())) return } p := &httpPublication{m: m, t: topic} id := req.Form.Get("id") h.RLock() for _, subscriber := range h.subscribers[topic] { if id == subscriber.id { // sub is sync; crufty rate limiting // so we don't hose the cpu subscriber.fn(p) } } h.RUnlock() }
func (c *Config) AuditLog(ctx context.Context, req *proto.AuditLogRequest, rsp *proto.AuditLogResponse) error { if req.Limit <= 0 { req.Limit = 10 } if req.Offset < 0 { req.Offset = 0 } if req.From < 0 { req.From = 0 } if req.To < 0 { req.To = 0 } logs, err := db.AuditLog(req.From, req.To, req.Limit, req.Offset, req.Reverse) if err != nil { return errors.InternalServerError("go.micro.srv.config.AuditLog", err.Error()) } rsp.Changes = logs return nil }
func (r *Rule) Update(ctx context.Context, req *proto.UpdateRequest, rsp *proto.UpdateResponse) error { if req.Rule == nil { return errors.BadRequest("go.micro.srv.router.Rule.Update", "invalid rule") } if len(req.Rule.Id) == 0 { return errors.BadRequest("go.micro.srv.router.Rule.Update", "invalid id") } if len(req.Rule.Service) == 0 { return errors.BadRequest("go.micro.srv.router.Rule.Update", "invalid service") } if len(req.Rule.Version) == 0 { return errors.BadRequest("go.micro.srv.router.Rule.Update", "invalid version") } if req.Rule.Weight < 0 || req.Rule.Weight > 100 { return errors.BadRequest("go.micro.srv.router.Rule.Update", "invalid weight, must be 0 to 100") } if err := rule.Update(req.Rule); err != nil { return errors.InternalServerError("go.micro.srv.router.Rule.Update", err.Error()) } return nil }
func TestClient(t *testing.T) { type TestResponse struct { Param string } response := []MockResponse{ {Method: "Foo.Bar", Response: map[string]interface{}{"foo": "bar"}}, {Method: "Foo.Struct", Response: &TestResponse{Param: "aparam"}}, {Method: "Foo.Fail", Error: errors.InternalServerError("go.mock", "failed")}, } c := NewClient(Response("go.mock", response)) for _, r := range response { req := c.NewJsonRequest("go.mock", r.Method, map[string]interface{}{"foo": "bar"}) var rsp interface{} err := c.Call(context.TODO(), req, &rsp) if err != r.Error { t.Fatalf("Expecter error %v got %v", r.Error, err) } t.Log(rsp) } }
func (r *Router) SelectStream(ctx context.Context, req *proto.SelectRequest, stream proto.Router_SelectStreamStream) error { // TODO: process filters if len(req.Service) == 0 { return errors.BadRequest("go.micro.srv.router.Router.Select", "invalid service name") } t := time.NewTicker(time.Duration(router.DefaultExpiry) * time.Second) defer t.Stop() for { services, err := router.Select(req.Service) if err != nil && err == selector.ErrNotFound { return errors.NotFound("go.micro.srv.router.Router.SelectStream", err.Error()) } else if err != nil { return errors.InternalServerError("go.micro.srv.router.Router.SelectStream", err.Error()) } if err := stream.Send(&proto.SelectResponse{ Services: services, Expires: time.Now().Unix() + int64(router.DefaultExpiry), }); err != nil { return err } <-t.C } return nil }
func (o *Oauth2) Introspect(ctx context.Context, req *oauth2.IntrospectRequest, rsp *oauth2.IntrospectResponse) error { // Who should be allowed to do this? if len(req.AccessToken) == 0 { return errors.BadRequest("go.micro.srv.auth", "invalid_request") } token, _, err := db.ReadToken(req.AccessToken) if err != nil { if err == db.ErrNotFound { rsp.Active = false return nil } return errors.InternalServerError("go.micro.srv.auth", "server_error") } if d := time.Now().Unix() - token.ExpiresAt; d > 0 { rsp.Active = false return nil } rsp.Token = token rsp.Active = true // should we really hand this over? rsp.Token.RefreshToken = "" return nil }
func (r *Label) Update(ctx context.Context, req *proto.UpdateRequest, rsp *proto.UpdateResponse) error { if req.Label == nil { return errors.BadRequest("go.micro.srv.router.Label.Update", "invalid label") } if len(req.Label.Id) == 0 { return errors.BadRequest("go.micro.srv.router.Label.Update", "invalid id") } if len(req.Label.Service) == 0 { return errors.BadRequest("go.micro.srv.router.Label.Update", "invalid service") } if len(req.Label.Key) == 0 { return errors.BadRequest("go.micro.srv.router.Label.Update", "invalid key") } if req.Label.Weight < 0 || req.Label.Weight > 100 { return errors.BadRequest("go.micro.srv.router.Label.Update", "invalid weight, must be 0 to 100") } if err := label.Update(req.Label); err != nil { return errors.InternalServerError("go.micro.srv.router.Label.Update", err.Error()) } return nil }
func (r *rpcClient) stream(ctx context.Context, address string, req Request) (Streamer, error) { msg := &transport.Message{ Header: make(map[string]string), } md, ok := c.GetMetadata(ctx) if ok { for k, v := range md { msg.Header[k] = v } } msg.Header["Content-Type"] = req.ContentType() cf, err := r.newCodec(req.ContentType()) if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } c, err := r.opts.Transport.Dial(address, transport.WithStream(), transport.WithTimeout(r.opts.DialTimeout)) if err != nil { return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) } var once sync.Once stream := &rpcStream{ context: ctx, request: req, once: once, closed: make(chan bool), codec: newRpcPlusCodec(msg, c, cf), } ch := make(chan error, 1) go func() { ch <- stream.Send(req.Request()) }() select { case err = <-ch: case <-time.After(r.opts.RequestTimeout): err = errors.New("go.micro.client", "request timeout", 408) } return stream, err }
func (g *grpcClient) stream(ctx context.Context, address string, req client.Request, opts client.CallOptions) (client.Streamer, error) { header := make(map[string]string) if md, ok := metadata.FromContext(ctx); ok { for k, v := range md { header[k] = v } } // set timeout in nanoseconds header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout) // set the content type for the request header["x-content-type"] = req.ContentType() md := gmetadata.New(header) ctx = gmetadata.NewContext(ctx, md) cf, err := g.newGRPCCodec(req.ContentType()) if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } // TODO: do not use insecure cc, err := grpc.Dial(address, grpc.WithCodec(cf), grpc.WithTimeout(opts.DialTimeout), grpc.WithInsecure()) if err != nil { return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) } desc := &grpc.StreamDesc{ StreamName: req.Service() + req.Method(), ClientStreams: true, ServerStreams: true, } st, err := grpc.NewClientStream(ctx, desc, cc, req.Method()) if err != nil { return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err)) } return &grpcStream{ context: ctx, request: req, closed: make(chan bool), stream: st, conn: cc, }, nil }
func (g *grpcClient) call(ctx context.Context, address string, req client.Request, rsp interface{}, opts client.CallOptions) error { header := make(map[string]string) if md, ok := metadata.FromContext(ctx); ok { for k, v := range md { header[k] = v } } // set timeout in nanoseconds header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout) // set the content type for the request header["x-content-type"] = req.ContentType() md := gmetadata.New(header) ctx = gmetadata.NewContext(ctx, md) cf, err := g.newGRPCCodec(req.ContentType()) if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } var grr error // TODO: do not use insecure cc, err := grpc.Dial(address, grpc.WithCodec(cf), grpc.WithTimeout(opts.DialTimeout), grpc.WithInsecure()) if err != nil { return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) } defer cc.Close() ch := make(chan error, 1) go func() { ch <- grpc.Invoke(ctx, req.Method(), req.Request(), rsp, cc) }() select { case err := <-ch: grr = err case <-ctx.Done(): grr = ctx.Err() } return grr }
func (s *Account) Delete(ctx context.Context, req *account.DeleteRequest, rsp *account.DeleteResponse) error { if len(req.Id) == 0 { return errors.BadRequest("go.micro.srv.auth.Delete", "invalid id") } if err := db.Delete(req.Id); err != nil { return errors.InternalServerError("go.micro.srv.auth.Delete", err.Error()) } return nil }
// Search srv handler func (es *Elastic) Search(ctx context.Context, req *proto.SearchRequest, rsp *proto.SearchResponse) error { result, err := elastic.Search(req) if err != nil { return errors.InternalServerError("go.micro.srv.elastic.Elastic.Search", err.Error()) } rsp.Result = result return nil }
func (e *Event) Search(ctx context.Context, req *event.SearchRequest, rsp *event.SearchResponse) error { recs, err := db.Search(req.Id, req.Type, req.From, req.To, req.Limit, req.Offset, req.Reverse) if err != nil { return errors.InternalServerError("go.micro.srv.event.Update", err.Error()) } rsp.Records = recs return nil }
func (s *Account) Update(ctx context.Context, req *account.UpdateRequest, rsp *account.UpdateResponse) error { // validate incoming if err := validateAccount(req.Account, "Update"); err != nil { return err } // need an account id for update if len(req.Account.Id) == 0 { return errors.BadRequest("go.micro.srv.auth.Update", "invalid id") } // lookup the record and verify it's the same acc, err := db.Read(req.Account.Id) if err != nil { return errors.InternalServerError("go.micro.srv.auth.Update", err.Error()) } // not the same client id if req.Account.ClientId != acc.ClientId { return errors.BadRequest("go.micro.srv.auth.Update", "invalid client id") } // hash the pass salt := db.Salt() h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.Account.ClientSecret), 10) if err != nil { return errors.InternalServerError("go.micro.srv.auth.Update", err.Error()) } pp := base64.StdEncoding.EncodeToString(h) // to lower req.Account.ClientId = strings.ToLower(req.Account.ClientId) req.Account.Type = strings.ToLower(req.Account.Type) // update if err := db.Update(req.Account, salt, pp); err != nil { return errors.InternalServerError("go.micro.srv.auth.Update", err.Error()) } return nil }
func (s *Account) Create(ctx context.Context, req *account.CreateRequest, rsp *account.CreateResponse) error { salt := random(16) h, err := bcrypt.GenerateFromPassword([]byte(x+salt+req.Password), 10) if err != nil { return errors.InternalServerError("go.micro.srv.user.Create", err.Error()) } pp := base64.StdEncoding.EncodeToString(h) req.User.Username = strings.ToLower(req.User.Username) req.User.Email = strings.ToLower(req.User.Email) return db.Create(req.User, salt, pp) }
func (r *rpcClient) Stream(ctx context.Context, request Request, opts ...CallOption) (Streamer, error) { var copts CallOptions for _, opt := range opts { opt(&copts) } next, err := r.opts.Selector.Select(request.Service(), copts.SelectOptions...) if err != nil && err == selector.ErrNotFound { return nil, errors.NotFound("go.micro.client", err.Error()) } else if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } var stream Streamer var grr error for i := 0; i < r.opts.Retries; i++ { node, err := next() if err != nil && err == selector.ErrNotFound { return nil, errors.NotFound("go.micro.client", err.Error()) } else if err != nil { return nil, errors.InternalServerError("go.micro.client", err.Error()) } address := node.Address if node.Port > 0 { address = fmt.Sprintf("%s:%d", address, node.Port) } stream, grr = r.stream(ctx, address, request) r.opts.Selector.Mark(request.Service(), node, grr) // bail early if succeeds if grr == nil { return stream, nil } } return stream, grr }
func (s *Account) Read(ctx context.Context, req *account.ReadRequest, rsp *account.ReadResponse) error { if len(req.Id) == 0 { return errors.BadRequest("go.micro.srv.auth.Read", "id cannot be blank") } acc, err := db.Read(req.Id) if err != nil { return errors.InternalServerError("go.micro.srv.auth.Read", err.Error()) } rsp.Account = acc return nil }
func (r *rpcClient) Call(ctx context.Context, request Request, response interface{}, opts ...CallOption) error { var copts CallOptions for _, opt := range opts { opt(&copts) } next, err := r.opts.Selector.Select(request.Service(), copts.SelectOptions...) if err != nil && err == selector.ErrNotFound { return errors.NotFound("go.micro.client", err.Error()) } else if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } var grr error for i := 0; i < r.opts.Retries; i++ { node, err := next() if err != nil && err == selector.ErrNotFound { return errors.NotFound("go.micro.client", err.Error()) } else if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } address := node.Address if node.Port > 0 { address = fmt.Sprintf("%s:%d", address, node.Port) } grr = r.call(ctx, address, request, response) r.opts.Selector.Mark(request.Service(), node, grr) // if the call succeeded lets bail early if grr == nil { return nil } } return grr }
func (c *Config) Read(ctx context.Context, req *proto.ReadRequest, rsp *proto.ReadResponse) error { if len(req.Id) == 0 { return errors.BadRequest("go.micro.srv.config.Read", "invalid id") } ch, err := db.Read(req.Id) if err != nil { return errors.InternalServerError("go.micro.srv.config.Read", err.Error()) } // Set response rsp.Change = ch if len(req.Path) == 0 { rsp.Change.Path = "" rsp.Change.Timestamp = 0 return nil } rsp.Change.Path = req.Path values, err := config.Values(&conf.ChangeSet{ Timestamp: time.Unix(ch.ChangeSet.Timestamp, 0), Data: []byte(ch.ChangeSet.Data), Checksum: ch.ChangeSet.Checksum, Source: ch.ChangeSet.Source, }) if err != nil { return errors.InternalServerError("go.micro.srv.config.Read", err.Error()) } parts := strings.Split(req.Path, config.PathSplitter) // we just want to pass back bytes rsp.Change.ChangeSet.Data = string(values.Get(parts...).Bytes()) return nil }
func (e *Event) Read(ctx context.Context, req *event.ReadRequest, rsp *event.ReadResponse) error { if len(req.Id) == 0 { return errors.BadRequest("go.micro.srv.event.Read", "invalid id") } rec, err := db.Read(req.Id) if err != nil { return errors.InternalServerError("go.micro.srv.event.Update", err.Error()) } rsp.Record = rec return nil }
func (r *Label) Delete(ctx context.Context, req *proto.DeleteRequest, rsp *proto.DeleteResponse) error { if len(req.Id) == 0 { return errors.BadRequest("go.micro.srv.router.Label.Delete", "invalid id") } if err := label.Delete(req.Id); err != nil { if err == db.ErrNotFound { return nil } return errors.InternalServerError("go.micro.srv.router.Label.Delete", err.Error()) } return nil }
func selector(id int, r router.Router) map[string]int { stats := make(map[string]int) // select the service next, err := r.Select(service) if err != nil { fmt.Println(id, "error selecting", err) return stats } for i := 1; i <= requests; i++ { // get a node node, err := next() if err != nil { fmt.Println(id, "error getting next", err) return stats } stats[node.Id]++ // make some request // client.Call(foo, request) req := client.NewRequest(service, "Router.Stats", &proto.StatsRequest{}) var dur time.Duration // lets set an error if d := (rand.Int() % i); d == 0 { dur = time.Millisecond * time.Duration(rand.Int()%20) err = errors.InternalServerError(service, "err") } else if d == 1 { dur = time.Second * 5 err = errors.New(service, "timed out", 408) } else { dur = time.Millisecond * time.Duration(rand.Int()%10) err = nil } // mark the result r.Mark(service, node, err) // record timing r.Record(req, node, dur, err) //fmt.Println(id, "selected", node.Id) time.Sleep(time.Millisecond*10 + time.Duration(rand.Int()%10)) } return stats }
func (m *Monitor) HealthChecks(ctx context.Context, req *proto.HealthChecksRequest, rsp *proto.HealthChecksResponse) error { if req.Limit == 0 { req.Limit = 10 } hcs, err := monitor.DefaultMonitor.HealthChecks(req.Id, req.Status, int(req.Limit), int(req.Offset)) if err != nil && err == monitor.ErrNotFound { return errors.NotFound("go.micro.srv.monitoring.Monitor.HealthCheck", err.Error()) } else if err != nil { return errors.InternalServerError("go.micro.srv.monitoring.Monitor.HealthCheck", err.Error()) } rsp.Healthchecks = hcs return nil }