// Copyright (c) Mainflux // SPDX-License-Identifier: Apache-2.0 package sdk import ( "crypto/tls" "errors" "fmt" "net/http" ) const ( // CTJSON represents JSON content type. CTJSON ContentType = "application/json" // CTJSONSenML represents JSON SenML content type. CTJSONSenML ContentType = "application/senml+json" // CTBinary represents binary content type. CTBinary ContentType = "application/octet-stream" ) const minPassLen = 8 var ( // ErrUnauthorized indicates that entity creation failed. ErrUnauthorized = errors.New("unauthorized, missing credentials") // ErrFailedCreation indicates that entity creation failed. ErrFailedCreation = errors.New("failed to create entity") // ErrFailedUpdate indicates that entity update failed. ErrFailedUpdate = errors.New("failed to update entity") // ErrFailedFetch indicates that fetching of entity data failed. ErrFailedFetch = errors.New("failed to fetch entity") // ErrFailedRemoval indicates that entity removal failed. ErrFailedRemoval = errors.New("failed to remove entity") // ErrFailedConnect indicates that connecting thing to channel failed. ErrFailedConnect = errors.New("failed to connect thing to channel") // ErrFailedDisconnect indicates that disconnecting thing from a channel failed. ErrFailedDisconnect = errors.New("failed to disconnect thing from channel") // ErrFailedPublish indicates that publishing message failed. ErrFailedPublish = errors.New("failed to publish message") // ErrFailedRead indicates that read messages failed. ErrFailedRead = errors.New("failed to read messages") // ErrInvalidContentType indicates that non-existent message content type // was passed. ErrInvalidContentType = errors.New("Unknown Content Type") // ErrFetchVersion indicates that fetching of version failed. ErrFetchVersion = errors.New("failed to fetch version") // ErrFailedWhitelist failed to whitelist configs ErrFailedWhitelist = errors.New("failed to whitelist") // ErrCerts indicates error fetching certificates. ErrCerts = errors.New("failed to fetch certs data") // ErrCertsRemove indicates failure while cleaning up from the Certs service. ErrCertsRemove = errors.New("failed to remove certificate") // ErrFailedCertUpdate failed to update certs in bootstrap config ErrFailedCertUpdate = errors.New("failed to update certs in bootstrap config") // ErrFailedUserAdd failed to add user to a group. ErrFailedUserAdd = errors.New("failed to add user to group") ) // ContentType represents all possible content types. type ContentType string var _ SDK = (*mfSDK)(nil) // User represents mainflux user its credentials. type User struct { ID string `json:"id,omitempty"` Email string `json:"email,omitempty"` Groups []string `json:"groups,omitempty"` Password string `json:"password,omitempty"` Metadata map[string]interface{} `json:"metadata,omitempty"` } // Group represents mainflux users group. type Group struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` ParentID string `json:"parent_id,omitempty"` Metadata map[string]interface{} `json:"metadata,omitempty"` } // Thing represents mainflux thing. type Thing struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Key string `json:"key,omitempty"` Metadata map[string]interface{} `json:"metadata,omitempty"` } // Channel represents mainflux channel. type Channel struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` Metadata map[string]interface{} `json:"metadata,omitempty"` } // SDK contains Mainflux API. type SDK interface { // CreateUser registers mainflux user. CreateUser(user User) (string, error) // User returns user object. User(token string) (User, error) // CreateToken receives credentials and returns user token. CreateToken(user User) (string, error) // UpdateUser updates existing user. UpdateUser(user User, token string) error // UpdatePassword updates user password. UpdatePassword(oldPass, newPass, token string) error // CreateThing registers new thing and returns its id. CreateThing(thing Thing, token string) (string, error) // CreateThings registers new things and returns their ids. CreateThings(things []Thing, token string) ([]Thing, error) // Things returns page of things. Things(token string, offset, limit uint64, name string) (ThingsPage, error) // ThingsByChannel returns page of things that are connected or not connected // to specified channel. ThingsByChannel(token, chanID string, offset, limit uint64, connected bool) (ThingsPage, error) // Thing returns thing object by id. Thing(id, token string) (Thing, error) // UpdateThing updates existing thing. UpdateThing(thing Thing, token string) error // DeleteThing removes existing thing. DeleteThing(id, token string) error // CreateGroup creates new group and returns its id. CreateGroup(group Group, token string) (string, error) // DeleteGroup deletes users group. DeleteGroup(id, token string) error // Groups returns page of users groups. Groups(token string, offset, limit uint64, name string) (GroupsPage, error) // Group returns users group object by id. Group(id, token string) (Group, error) // Assign assigns user to a group. Assign(userID, groupID, token string) error // Unassign removes user from a group. Unassign(userID, groupID, token string) error // Members lists member users of a group. Members(groupID, token string, offset, limit uint64) (UsersPage, error) // Memberships lists groups for user. Memberships(userID, token string, offset, limit uint64) (GroupsPage, error) // UpdateGroup updates existing group. UpdateGroup(group Group, token string) error // Connect bulk connects things to channels specified by id. Connect(conns ConnectionIDs, token string) error // DisconnectThing disconnect thing from specified channel by id. DisconnectThing(thingID, chanID, token string) error // CreateChannel creates new channel and returns its id. CreateChannel(channel Channel, token string) (string, error) // CreateChannels registers new channels and returns their ids. CreateChannels(channels []Channel, token string) ([]Channel, error) // Channels returns page of channels. Channels(token string, offset, limit uint64, name string) (ChannelsPage, error) // ChannelsByThing returns page of channels that are connected or not connected // to specified thing. ChannelsByThing(token, thingID string, offset, limit uint64, connected bool) (ChannelsPage, error) // Channel returns channel data by id. Channel(id, token string) (Channel, error) // UpdateChannel updates existing channel. UpdateChannel(channel Channel, token string) error // DeleteChannel removes existing channel. DeleteChannel(id, token string) error // SendMessage send message to specified channel. SendMessage(chanID, msg, token string) error // ReadMessages read messages of specified channel. ReadMessages(chanID, token string) (MessagesPage, error) // SetContentType sets message content type. SetContentType(ct ContentType) error // Version returns used mainflux version. Version() (string, error) // AddBootstrap add bootstrap configuration AddBootstrap(token string, cfg BootstrapConfig) (string, error) // View returns Thing Config with given ID belonging to the user identified by the given token. ViewBootstrap(token, id string) (BootstrapConfig, error) // Update updates editable fields of the provided Config. UpdateBootstrap(token string, cfg BootstrapConfig) error // Update boostrap config certificates UpdateBootstrapCerts(token string, id string, clientCert, clientKey, ca string) error // Remove removes Config with specified token that belongs to the user identified by the given token. RemoveBootstrap(token, id string) error // Bootstrap returns Config to the Thing with provided external ID using external key. Bootstrap(externalKey, externalID string) (BootstrapConfig, error) // Whitelist updates Thing state Config with given ID belonging to the user identified by the given token. Whitelist(token string, cfg BootstrapConfig) error // IssueCert issues a certificate for a thing required for mtls. IssueCert(thingID string, keyBits int, keyType, valid, token string) (Cert, error) // RemoveCert removes a certificate RemoveCert(id, token string) error // RevokeCert revokes certificate with certID for thing with thingID RevokeCert(thingID, certID, token string) error } type mfSDK struct { baseURL string readerURL string bootstrapURL string certsURL string readerPrefix string usersPrefix string groupsPrefix string thingsPrefix string certsPrefix string channelsPrefix string httpAdapterPrefix string bootstrapPrefix string msgContentType ContentType client *http.Client } // Config contains sdk configuration parameters. type Config struct { BaseURL string ReaderURL string BootstrapURL string CertsURL string ReaderPrefix string UsersPrefix string GroupsPrefix string ThingsPrefix string HTTPAdapterPrefix string BootstrapPrefix string MsgContentType ContentType TLSVerification bool } // NewSDK returns new mainflux SDK instance. func NewSDK(conf Config) SDK { return &mfSDK{ baseURL: conf.BaseURL, readerURL: conf.ReaderURL, bootstrapURL: conf.BootstrapURL, certsURL: conf.CertsURL, readerPrefix: conf.ReaderPrefix, usersPrefix: conf.UsersPrefix, groupsPrefix: conf.GroupsPrefix, thingsPrefix: conf.ThingsPrefix, httpAdapterPrefix: conf.HTTPAdapterPrefix, bootstrapPrefix: conf.BootstrapPrefix, msgContentType: conf.MsgContentType, client: &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: !conf.TLSVerification, }, }, }, } } func (sdk mfSDK) sendRequest(req *http.Request, token, contentType string) (*http.Response, error) { if token != "" { req.Header.Set("Authorization", token) } if contentType != "" { req.Header.Add("Content-Type", contentType) } return sdk.client.Do(req) } func createURL(baseURL, prefix, endpoint string) string { if prefix == "" { return fmt.Sprintf("%s/%s", baseURL, endpoint) } return fmt.Sprintf("%s/%s/%s", baseURL, prefix, endpoint) }