Example #1
0
func (self *Storage) Status() (success bool, err error) {
	defer func() {
		if recv := recover(); recv != nil {
			success = false
			err = recv.(error)
			return
		}
	}()

	fake_id, _ := util.GenUUID4()
	key := "status_" + fake_id
	mc, err := self.getMC()
	defer self.returnMC(mc)
	if err != nil {
		return false, err
	}
	err = mc.Set("status_"+fake_id, "test", 6*time.Second)
	if err != nil {
		return false, err
	}
	var val string
	err = mc.Get(key, &val)
	if err != nil || val != "test" {
		return false, errors.New("Invalid value returned")
	}
	mc.Delete(key, time.Duration(0))
	return true, nil
}
Example #2
0
// A client connects!
func (self *Serv) Hello(worker *Worker, cmd PushCommand, sock *PushWS) (result int, arguments util.JsMap) {
	var uaid string

	args := cmd.Arguments.(util.JsMap)
	if self.logger != nil {
		chidss := ""
		if chids, ok := args["channelIDs"]; ok {
			chidss = "[" + strings.Join(chids.([]string), ", ") + "]"
		}
		self.logger.Info("server", "handling 'hello'",
			util.Fields{"uaid": args["uaid"].(string),
				"channelIDs": chidss})
	}

	// TODO: If the client needs to connect to a different server,
	// Look up the appropriate server (based on UAID)
	// return a response that looks like:
	// { uaid: UAIDValue, status: 302, redirect: NewWS_URL }

	// New connects overwrite previous connections.
	// Raw client
	if args["uaid"] == "" {
		uaid, _ = util.GenUUID4()
		if self.logger != nil {
			self.logger.Debug("server",
				"Generating new UAID",
				util.Fields{"uaid": uaid})
		}
	} else {
		uaid = args["uaid"].(string)
		if self.logger != nil {
			self.logger.Debug("server",
				"Using existing UAID",
				util.Fields{"uaid": uaid})
		}
		delete(args, "uaid")
	}

	prop := self.Set_proprietary_info(args)
	if self.logger != nil {
		self.logger.Debug("server", "Proprietary Info",
			util.Fields{"ip": prop.Ip,
				"port": prop.Port})
	}

	// Create a new, live client entry for this record.
	// See Bye for discussion of potential longer term storage of this info
	sock.Uaid = uaid
	client := &Client{
		Worker: worker,
		PushWS: *sock,
		UAID:   uaid,
		Prop:   prop,
	}
	MuClient.Lock()
	Clients[uaid] = client
	MuClient.Unlock()
	MetricIncrement("updates.client.connect")

	// We don't register the list of known ChannelIDs since we echo
	// back any ChannelIDs sent on behalf of this UAID.
	args["uaid"] = uaid
	arguments = args
	result = 200
	return result, arguments
}
Example #3
0
// Associate the UAID for this socket connection (and flush any data that
// may be pending for the connection)
func (self *Worker) Hello(sock *PushWS, buffer interface{}) (err error) {
	// register the UAID
	defer func() {
		if r := recover(); r != nil {
			debug.PrintStack()
			if self.logger != nil {
				self.logger.Error("worker",
					"Unhandled error",
					util.Fields{"cmd": "hello", "error": r.(error).Error()})
			}
			err = sperrors.InvalidDataError
		}
	}()

	//Force the client to re-register all it's clients.
	// This is done by returning a new UAID.
	forceReset := false

	var suggestedUAID string

	data := buffer.(util.JsMap)
	if _, ok := data["uaid"]; !ok {
		// Must include "uaid" (even if blank)
		data["uaid"] = ""
	}
	if redir, ok := self.config["db.redirect"]; ok {
		resp := util.JsMap{
			"messageType": data["messageType"],
			"status":      302,
			"redirect":    redir,
			"uaid":        sock.Uaid}
		if self.logger != nil {
			self.logger.Debug("worker", "sending redirect",
				util.Fields{"messageType": data["messageType"].(string),
					"status":   strconv.FormatInt(data["status"].(int64), 10),
					"redirect": data["redirect"].(string),
					"uaid":     data["uaid"].(string)})
		}
		websocket.JSON.Send(sock.Socket, resp)
		return nil
	}
	suggestedUAID = data["uaid"].(string)
	if data["channelIDs"] == nil {
		// Must include "channelIDs" (even if empty)
		if self.logger != nil {
			self.logger.Debug("worker", "Missing ChannelIDs", nil)
		}
		return sperrors.MissingDataError
	}
	if len(sock.Uaid) > 0 &&
		len(data["uaid"].(string)) > 0 &&
		sock.Uaid != suggestedUAID {
		// if there's already a Uaid for this channel, don't accept a new one
		if self.logger != nil {
			self.logger.Debug("worker", "Conflicting UAIDs", nil)
		}
		return sperrors.InvalidChannelError
	}
	if self.filter.Find([]byte(strings.ToLower(suggestedUAID))) != nil {
		if self.logger != nil {
			self.logger.Debug("worker", "Invalid character in UAID", nil)
		}
		return sperrors.InvalidChannelError
	}
	if len(sock.Uaid) == 0 {
		// if there's no UAID for the socket, accept or create a new one.
		sock.Uaid = suggestedUAID
		if len(sock.Uaid) > UAID_MAX_LEN {
			if self.logger != nil {
				self.logger.Debug("worker", "UAID is too long", nil)
			}
			return sperrors.InvalidDataError
		}
		if len(sock.Uaid) == 0 {
			forceReset = forceReset || true
		}
		if ClientCollision(sock.Uaid) {
			forceReset = true
		}
		if num := len(data["channelIDs"].([]interface{})); num > 0 {
			// are there a suspicious number of channels?
			if int64(num) > self.maxChannels {
				forceReset = forceReset || true
			}
			if !sock.Store.IsKnownUaid(sock.Uaid) {
				forceReset = forceReset || true
			}
		}
	}
	if forceReset {
		if self.logger != nil {
			self.logger.Warn("worker", "Resetting UAID for device",
				util.Fields{"uaid": sock.Uaid})
		}
		if len(sock.Uaid) > 0 {
			sock.Store.PurgeUAID(sock.Uaid)
		}
		sock.Uaid, _ = util.GenUUID4()
	}
	// register the sockets (NOOP)
	// register any proprietary connection requirements
	// alert the master of the new UAID.
	cmd := PushCommand{
		Command: HELLO,
		Arguments: util.JsMap{
			"worker": self,
			"uaid":   sock.Uaid,
			"chids":  data["channelIDs"],
		},
	}
	// blocking call back to the boss.
	raw_result, args := HandleServerCommand(cmd, sock)
	result := PushCommand{raw_result, args}
	if err = sock.Store.SetUAIDHost(sock.Uaid, ""); err != nil {
		return err
	}

	if self.logger != nil {
		self.logger.Debug("worker", "sending response",
			util.Fields{"cmd": "hello", "error": ErrStr(err),
				"uaid": sock.Uaid})
	}
	// websocket.JSON.Send(sock.Socket, util.JsMap{
	// 	"messageType": data["messageType"],
	// 	"status":      result.Command,
	// 	"uaid":        sock.Uaid})
	msg := []byte("{\"messageType\":\"" + data["messageType"].(string) +
		"\",\"status\":" + strconv.FormatInt(int64(result.Command), 10) +
		",\"uaid\":\"" + sock.Uaid + "\"}")
	_, err = sock.Socket.Write(msg)

	self.state = ACTIVE
	if err == nil {
		// Get the lastAccessed time from wherever
		return self.Flush(sock, 0, "", 0)
	}
	return err
}
Example #4
0
// Register a new device to a given userID.
func (self *Storage) RegisterDevice(userid string, dev Device) (devId string, err error) {
	// value check?
	statement := "insert into deviceInfo (deviceId, lockable, loggedin, lastExchange, hawkSecret, accepts, pushUrl) values ($1, $2, $3, $4, $5, $6, $7);"
	if dev.ID == "" {
		dev.ID, _ = util.GenUUID4()
	}
	dbh := self.db
	if err != nil {
		self.logger.Error(self.logCat, "Could not insert device",
			util.Fields{"error": err.Error()})
		return "", err
	}
	if _, err = dbh.Exec(statement,
		string(dev.ID),
		dev.Lockable,
		dev.LoggedIn,
		dbNow(),
		dev.Secret,
		dev.Accepts,
		dev.PushUrl); err != nil {
		if strings.Contains(err.Error(), "duplicate key value") {
			fmt.Printf("#### Updating... \n")
			statement = "update deviceinfo set lockable=$2, accepts=$3, pushUrl=$4, hawkSecret=$5 where deviceId=$1"
			if _, err = dbh.Exec(statement,
				string(dev.ID),
				dev.Lockable,
				dev.Accepts,
				dev.PushUrl,
				dev.Secret,
			); err != nil {
				self.logger.Error(self.logCat, "Could not update device",
					util.Fields{"error": err.Error(),
						"device": fmt.Sprintf("%+v", dev)})
				return "", err
			}
			statement = "update usertodevicemap set name = $1 where deviceId=$2 and userId=$3"
			if _, err = dbh.Exec(statement,
				string(dev.Name),
				string(dev.ID),
				userid,
			); err != nil {
				self.logger.Error(self.logCat,
					"Could not update device name",
					util.Fields{"error": err.Error(),
						"device": fmt.Sprintf("%+v", dev),
						"userid": userid})
				return "", err
			}
		} else {
			self.logger.Error(self.logCat, "Could not create device",
				util.Fields{"error": err.Error(),
					"device": fmt.Sprintf("%+v", dev)})
			return "", err
		}
	} else {
		if _, err = dbh.Exec("insert into userToDeviceMap (userId, deviceId, name) values ($1, $2, $3);", userid, dev.ID, dev.Name); err != nil {
			switch {
			default:
				self.logger.Error(self.logCat,
					"Could not map device to user",
					util.Fields{
						"uid":      userid,
						"deviceId": dev.ID,
						"name":     dev.Name,
						"error":    err.Error()})
				return "", err
			}
		}
	}
	return dev.ID, nil
}
Example #5
0
func (self *Handler) Register(resp http.ResponseWriter, req *http.Request) {
	/*register a new device
	 */

	var buffer util.JsMap = util.JsMap{}
	var userid string
	var user string
	var pushUrl string
	var deviceid string
	var secret string
	var accepts string
	var lockable bool
	var ok bool

	self.logCat = "handler:Register"

	buffer, err := parseBody(req.Body)
	if err != nil {
		http.Error(resp, "No body", http.StatusBadRequest)
	} else {
		if assertion, ok := buffer["assert"].(string); !ok {
			self.logger.Error(self.logCat, "Missing assertion", nil)
			http.Error(resp, "Unauthorized", 401)
			return
		} else {
			userid, user, err = self.verifyAssertion(assertion)
			if err != nil {
				http.Error(resp, "Unauthorized", 401)
			}
			self.logger.Info(self.logCat, "### Got user "+userid, nil)
			user = strings.SplitN(user, "@", 2)[0]
		}

		if _, ok = buffer["pushurl"]; !ok {
			self.logger.Error(self.logCat, "Missing SimplePush url", nil)
			http.Error(resp, "Bad Data", 400)
			return
		} else {
			pushUrl = buffer["pushurl"].(string)
		}
		//ALWAYS generate a new secret on registration!
		secret = GenNonce(16)
		if _, ok = buffer["deviceid"]; !ok {
			deviceid, err = util.GenUUID4()
		} else {
			deviceid = buffer["deviceid"].(string)
		}
		if _, ok = buffer["has_passcode"]; !ok {
			lockable = true
		} else {
			lockable, err = strconv.ParseBool(buffer["has_passcode"].(string))
			if err != nil {
				lockable = false
			}
		}
		if k, ok := buffer["accepts"]; ok {
			// collapse the array to a string
			if l := len(k.([]interface{})); l > 0 {
				acc := make([]byte, l)
				for n, ke := range k.([]interface{}) {
					acc[n] = ke.(string)[0]
				}
				accepts = strings.ToLower(string(acc))
			}
		}
		if len(accepts) == 0 {
			accepts = "elrth"
		}

		// create the new device record
		var devId string
		if devId, err = self.store.RegisterDevice(
			userid,
			storage.Device{
				ID:       deviceid,
				Name:     user,
				Secret:   secret,
				PushUrl:  pushUrl,
				Lockable: lockable,
				Accepts:  accepts,
			}); err != nil {
			self.logger.Error(self.logCat, "Error Registering device", nil)
			http.Error(resp, "Bad Request", 400)
			return
		} else {
			if devId != deviceid {
				self.logger.Error(self.logCat, "Different deviceID returned",
					util.Fields{"original": deviceid, "new": devId})
				http.Error(resp, "Server error", 500)
				return
			}
			self.devId = deviceid
		}
	}
	self.metrics.Increment("registration")
	resp.Write([]byte(fmt.Sprintf("{\"deviceid\":\"%s\", \"secret\":\"%s\"}",
		self.devId,
		secret)))
	return
}