Example #1
0
func login_check(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	var login string
	if r.Method == "GET" {
		cookie, err := r.Cookie("sessionToken")
		if err == nil {
			cookie_uuid, parse_error := gocql.ParseUUID(strings.TrimPrefix(cookie.String(), "sessionToken="))
			if parse_error != nil {
				w.WriteHeader(403)
				fmt.Fprintf(w, "{\"error\":\"unauthorized\"}\n")
				return
			}
			if request_err := session.Query("select login from cookies where cookie = ?", cookie_uuid).Consistency(gocql.One).Scan(&login); request_err != nil {
				if request_err == gocql.ErrNotFound {
					w.WriteHeader(403)
					fmt.Fprintf(w, "{\"error\":\"unauthorized\"}\n")
					return
				} else {
					w.WriteHeader(500)
					return
				}
			}
			fmt.Fprintf(w, "{\"status\":\"You logged in!\"}\n")
		} else {
			w.WriteHeader(403)
			fmt.Fprintf(w, "{\"error\":\"unauthorized\"}\n")
			return
		}
	} else {
		w.WriteHeader(405)
		fmt.Fprintf(w, "{\"error\":\"Allowed methods: GET\"}\n")
	}
}
Example #2
0
func (asset *Asset) Find(session *gocql.Session, assetId string) (*Asset, error) {
	var id gocql.UUID
	var name string
	var path string
	var contentType string
	var createdAt time.Time
	var binary []byte

	// Check if the assetId is an valid UUID
	idCheck, err := gocql.ParseUUID(assetId)
	if err != nil {
		return nil, err
	}

	if idCheck.Timestamp() == 0 {
		return nil, errors.New("Invalid UUID")
	}

	if err := session.Query(`SELECT id, name, path, contenttype, createdat, binary FROM assets WHERE id = ? LIMIT 1`,
		assetId).Consistency(gocql.One).Scan(&id, &name, &path, &contentType, &createdAt, &binary); err != nil {
		return nil, err
	}

	return &Asset{id, name, strings.Split(path, ","), contentType, createdAt, binary}, nil
}
Example #3
0
func (c *Command) Execute(message []byte) {

	if !c.connection.GetServerAuthState() {
		return
	}

	var commandDetector CommandDetector
	json.Unmarshal(message, &commandDetector)

	var isLock bool = false

	userUUID, err := gocql.ParseUUID(commandDetector.UserUUID)
	if err != nil {

	} else {

		user, err := model_user.Get(userUUID)
		logger.String(fmt.Sprintf("commandDetector.UserUUID %+v, user %+v", commandDetector.UserUUID, user))
		if err == nil && user != nil && user.IsLock {
			isLock = true
		}
	}

	b, _ := json.Marshal(map[string]interface{}{
		"command":    "answer",
		"command_id": commandDetector.CommandId,
		"is_lock":    isLock,
	})

	c.connection.Send(string(b))
}
func (conn *CassConnection) LookupDeviceByStringID(
	id string) (datalayer.Device, error) {

	deviceId, err := gocql.ParseUUID(id)
	if err != nil {
		canolog.Error(err)
		return nil, err
	}
	return conn.LookupDevice(deviceId)
}
func mockExercise() *sitrep.ExerciseByIdentifier {
	uuid, err := gocql.ParseUUID("582412e9-6e2b-493f-b5ed-889f42584861")
	if err != nil {
		panic(err)
	}
	return &sitrep.ExerciseByIdentifier{
		Id:                  uuid,
		ExerciseDescription: "Beta Exercise Description",
		ExerciseName:        "Beta Exercise",
		HasActivation:       true,
		IsActive:            true,
		ActiveUntil:         time.Now().Add(time.Hour * 72),
	}
}
Example #6
0
func LoadOrCreateSession(uuid string, remoteAddr string, userAgent string) *Session {

	s := New()

	var err error
	s.UUID, err = gocql.ParseUUID(uuid)
	if err == nil {
		s.Load()
	}

	if !s.Exists || (len(remoteAddr) > 0 && remoteAddr != s.RemoteAddr) || userAgent != s.UserAgent {
		logger.String(fmt.Sprintf("remoteAddr %s %s, userAgent %s %s", remoteAddr, s.RemoteAddr, userAgent, s.UserAgent))
		s.Create(remoteAddr, userAgent)
	}

	return s
}
Example #7
0
func (d *D) loadService(servicename string) (*S, error) {
	if servicename == "" {
		return nil, errors.New("No service name has been specified")
	}

	cluster := gocql.NewCluster(d.cluster)
	cluster.Keyspace = d.keyspace
	session, err := cluster.CreateSession()
	if err != nil {
		return nil, err
	}
	defer session.Close()

	var ii, an, av string

	s := S{name: servicename}
	iMap := make(map[string]*I)

	iter := session.Query("SELECT instance_id, attribute_name, attribute_value FROM attributes WHERE service_name = ?", servicename).Iter()
	for iter.Scan(&ii, &an, &av) {
		var i *I
		var ok bool
		if i, ok = iMap[ii]; !ok {
			var id gocql.UUID
			var err error
			if id, err = gocql.ParseUUID(ii); err != nil {
				return nil, errors.New("could not parse instance id " + ii)
			}

			i = &I{id: id, attributes: make(map[string]string)}
			iMap[ii] = i
		}
		i.attributes[an] = av
	}
	if err := iter.Close(); err != nil {
		return nil, err
	}

	s.instances = iMap
	return &s, nil
}
func exercisify(inner func(http.ResponseWriter, *http.Request, *sitrep.UsersByEmail, *sitrep.ExerciseByIdentifier), h *Handler, requireAuthentication bool) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		exerciseIDRaw, err := parseExerciseID(r)
		if err != nil {
			makeForbidden(w, err)
			return
		}

		exerciseID, err := gocql.ParseUUID(exerciseIDRaw)
		if err != nil {
			makeForbidden(w, err)
			return
		}

		exercise, err := models.FindExerciseByID(h.Cassandra, exerciseID)
		if err != nil {
			makeForbidden(w, err)
			return
		}
		if !requireAuthentication {
			inner(w, r, nil, exercise)
			return
		}
		counter := metrics.GetOrRegisterCounter(statAuthFail, h.statMap)
		accessToken, err := parseCredentials(r)
		if err != nil {
			counter.Inc(1)
			makeForbidden(w, err)
			return
		}

		user, err := models.VerifyUserRequest(h.Cassandra, accessToken)
		if err != nil {
			counter.Inc(1)
			makeForbidden(w, err)
			return
		}
		inner(w, r, user, exercise)
	})
}
func exercisifyOnly(inner func(http.ResponseWriter, *http.Request, *sitrep.ExerciseByIdentifier), h *Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		exerciseIDRaw, err := parseExerciseID(r)
		if err != nil {
			makeForbidden(w, err)
			return
		}

		exerciseID, err := gocql.ParseUUID(exerciseIDRaw)
		if err != nil {
			makeForbidden(w, err)
			return
		}

		exercise, err := models.FindExerciseByID(h.Cassandra, exerciseID)
		if err != nil {
			makeForbidden(w, err)
			return
		}
		inner(w, r, exercise)
	})
}
Example #10
0
func logout(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	cookie, err := r.Cookie("sessionToken")
	if r.Method == "POST" {
		if err == nil {
			cookie_uuid, parse_error := gocql.ParseUUID(strings.TrimPrefix(cookie.String(), "sessionToken="))
			if parse_error != nil {
				w.WriteHeader(400)
				fmt.Fprintf(w, "{\"error\":\"bad cookie\"}\n")
				return
			}
			if request_err := session.Query("delete from cookies where cookie = ?", cookie_uuid).Exec(); request_err != nil {
				fmt.Println(request_err)
				w.WriteHeader(500)
				return
			}
		}
		fmt.Fprintf(w, "{\"error\":\"\"}\n")
	} else {
		w.WriteHeader(405)
		fmt.Fprintf(w, "{\"error\":\"Allowed methods: GET\"}\n")
	}
}
Example #11
0
// Lookup device by ID string in the URL.  The ID string may be a UUID or
// "self".  Verifies that the requester has permission to access to the
// requested device, returning an error if unathorized.
func getDeviceByIdString(info *RestRequestInfo) (datalayer.Device, RestError) {
	deviceIdString := info.URLVars["id"]

	if deviceIdString == "self" {
		if info.Device == nil {
			// TODO: should be unauthorized
			return nil, BadInputError("Expected device credentials with /api/device/self").Log()
		}
		return info.Device, nil
	} else {
		uuid, err := gocql.ParseUUID(deviceIdString)
		if err != nil {
			return nil, URLNotFoundError()
		}

		// TODO: support anonymous device creation

		if info.Account != nil {
			device, err := info.Account.Device(uuid)
			if err != nil {
				// TODO: What errors to return here?
				return nil, InternalServerError("Device lookup failed").Log()
			}
			return device, nil
		} else if info.Device != nil {
			if deviceIdString != string(info.Device.IDString()) {
				// TODO: what error to return?
				// TODO: This should be allowed if the device has adequate
				// permissions.
				return nil, InternalServerError("Device mismatch").Log()
			}
			return info.Device, nil
		} else {
			return nil, NotLoggedInError()
		}
	}
}
Example #12
0
func main() {

	log.SetFlags(log.Llongfile)

	expvar.Publish("Goroutines", expvar.Func(goroutines))
	runtime.GOMAXPROCS(6)

	var err *errors.Error

	config, err = readConfig()

	if err != nil {
		// logger.Error(fmt.Sprintf("readConfig - %v", err))
		log.Fatal(err)
		// log.Fatal("ListenAndServe: ", err)
		os.Exit(0)
	}

	logger.Init(config.Logger.Path)

	if config.Daemonize {

		flag.Parse()
		daemon.AddCommand(daemon.StringFlag(signal, "quit"), syscall.SIGQUIT, termHandler)
		daemon.AddCommand(daemon.StringFlag(signal, "stop"), syscall.SIGTERM, termHandler)
		daemon.AddCommand(daemon.StringFlag(signal, "reload"), syscall.SIGHUP, reloadHandler)

		cntxt := &daemon.Context{
			PidFileName: config.PidFilepath,
			PidFilePerm: 0644,
			LogFileName: config.Logger.Path + "/stdout.log",
			LogFilePerm: 0640,
			WorkDir:     "./",
			Umask:       027,
			Args:        []string{"[spacecraft-online]"},
		}

		if len(daemon.ActiveFlags()) > 0 {
			d, err := cntxt.Search()
			if err != nil {
				log.Fatalln("Unable send signal to the daemon:", err)
			}
			daemon.SendCommands(d)
			return
		}

		d, err := cntxt.Reborn()
		if err != nil {
			log.Fatalln(err)
		}
		if d != nil {
			return
		}
		defer cntxt.Release()

	}

	logger.String(fmt.Sprintf("started"))

	cluster := gocql.NewCluster(config.Cassandra.IP)
	cluster.Keyspace = "sc_2"
	cluster.Consistency = 1

	session, berr := cluster.CreateSession()

	model_server.Init(session)
	ip, t := localIP()
	if t != nil {
		logger.Error(errors.New(t))
		os.Exit(0)
	}

	server := model_server.New(ip, config.Http.Port)
	model.Init(server.UUID, session)

	server.StartUpdater()
	star.SetLocalServer(server)

	bdispatcher := buildings.NewDispatcher(config.Buildings.PoolSize)

	model2.InstallModels(session,
		server.UUID,
		model2_auth_session.InstallInfo,
		model2_user.InstallInfo,
		model2_live_planet.InstallInfo,
		model2_building.InstallInfo,
		model2_player.InstallInfo)

	var connectionFactory = factory.New()

	// clients commands
	connectionFactory.InstallCommand("auth", cmd_auth.Generator)
	connectionFactory.InstallCommand("logout", cmd_logout.Generator)
	connectionFactory.InstallCommand("set_section", cmd_set_section.Generator)
	connectionFactory.InstallCommand("start", cmd_start.Generator)
	connectionFactory.InstallCommand("get_planet", cmd_get_planet.Generator)
	connectionFactory.InstallCommand("get_planet_buildings_for_construct", cmd_get_planet_buildings_for_construct.Generator)
	connectionFactory.InstallCommand("build", cmd_build.Generator)

	// star commands
	connectionFactory.InstallCommand("get_session_lock_state", cmd_session_lock_state.Generator)
	connectionFactory.InstallCommand("get_user_lock_state", cmd_user_lock_state.Generator)
	connectionFactory.InstallCommand("star_user_logout", cmd_user_logout.Generator)

	commandContext := &command.Context{Factory: connectionFactory, CQLSession: session, Config: config, ServerUUID: server.UUID, BDispatcher: bdispatcher}

	star.SetCommands(connectionFactory.GetCommands(), commandContext)

	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {

		logger.String("/ws")
		if r.Method != "GET" {
			http.Error(w, "Method not allowed", 405)
			return
		}

		ws, err := connection.Upgrader.Upgrade(w, r, nil)
		if err != nil {
			logger.Error(errors.New(err))
			return
		}

		ra := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
		c := connectionFactory.CreateConnection(ws, commandContext, ra, r.Header["User-Agent"][0])
		// logger.String(ra)
		// logger.String(r.Header["User-Agent"][0])
		logger.String(fmt.Sprintf("accept connection %v", c.Id))
		// go c.Writing()
		c.Reading()
		c.Close()
		logger.String(fmt.Sprintf("close connection %v", c.Id))
	})

	http.HandleFunc("/debug", func(w http.ResponseWriter, r *http.Request) {
		b, err := json.Marshal(connectionFactory.MakeDebugInfo())
		if err != nil {
			logger.Error(errors.New(err))
		}
		io.WriteString(w, string(b))
	})

	http.HandleFunc("/api/auth/success", func(w http.ResponseWriter, r *http.Request) {

		logger.String("/api/auth/success")

		/*
			ra := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")]
			logger.String("remoteAdder " + ra)
			logger.String(fmt.Sprintf("%+v", r.Header))
		*/

		client := &http.Client{}
		req, err := http.NewRequest("GET", "http://auth.spacecraft-online.org/api/check_token?token="+r.URL.Query().Get("token"), nil)
		if err != nil {
			logger.Error(errors.New(err))
			return
		}

		resp, err := client.Do(req)
		if err != nil {
			logger.Error(errors.New(err))
			return
		}

		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			logger.Error(errors.New(err))
			return
		}

		if string(body) != "{\"status\":\"ok\",\"result\":true}" {
			logger.String(string(body))
			http.Redirect(w, r, "/", http.StatusMovedPermanently)
			// logger.Error(errors.New(err))
			return
		}

		// logger.String(string(body))

		sessionUUID, err := gocql.ParseUUID(r.URL.Query().Get("session_uuid"))
		if err != nil {
			http.Redirect(w, r, "/", http.StatusMovedPermanently)
			return
		}

		session, err := model2_auth_session.Get(sessionUUID)
		if err != nil || session == nil {
			http.Redirect(w, r, "/", http.StatusMovedPermanently)
			return
		}

		// session := model_auth_session.LoadOrCreateSession(session_uuid, "", r.Header["User-Agent"][0])

		method := r.URL.Query().Get("method")
		unique := r.URL.Query().Get("unique")
		user, _ := model2_user.GetByMethod(method, unique)

		if session.IsAuth {

			// check for another user and relogin
			if user.Exists && user.UUID.String() != session.UserUUID.String() {

				user.AddMethod(method, unique)

			} else {

			}

		} else {

			// loging
			if !user.Exists {
				user, _ = model2_user.Create()
				user.Update(model2.Fields{
					"Name": r.URL.Query().Get("username"),
				})
				user.AddMethod(method, unique)
			}

		}

		session.Update(model2.Fields{
			"IsAuth":     true,
			"UserUUID":   user.UUID,
			"AuthMethod": method,
		})

		http.Redirect(w, r, "/", http.StatusMovedPermanently)
	})

	listen := fmt.Sprintf(":%v", config.Http.Port)
	logger.String(fmt.Sprintf("listen http %v", listen))
	berr = http.ListenAndServe(listen, nil)
	if berr != nil {
		// logger.Error(fmt.Sprintf("ListenAndServe - %v", err))
		logger.Error(errors.New(berr))
		// log.Fatal("ListenAndServe: ", err)
		os.Exit(0)
	}

	go worker()

	derr := daemon.ServeSignals()
	if derr != nil {
		log.Println("Error:", derr)
	}
	// log.Println("daemon terminated")
	logger.String(fmt.Sprintf("daemon terminated"))

}
Example #13
0
func (c *Command) Execute(message []byte) {

	var commandDetector CommandDetector
	json.Unmarshal(message, &commandDetector)

	// inner connection auth
	if commandDetector.ServerUUID != nil {
		ServerUUID, _ := gocql.ParseUUID(*commandDetector.ServerUUID)
		// todo: check err
		server := model_server.Get(ServerUUID)
		answer := "error"
		if server.Exists && c.connection.GetRemoteAddr() == server.IP {
			c.connection.SetServerAuthState()
			answer = "ok"
		}

		c.connection.Send(`{"command":"` + answer + `"}`)
		return
	}

	// ---------------
	var session *model2_auth_session.Fields

	sessionUUID, err := gocql.ParseUUID(commandDetector.SessionUUID)
	if err == nil {
		session, err = model2_auth_session.Load(sessionUUID)
		if session != nil {
			if session.Exists {
				if session.RemoteAddr != c.connection.GetRemoteAddr() || session.UserAgent != c.connection.GetUserAgent() {
					session = nil
				}
			} else {
				session = nil
			}
		}
	}

	if err != nil || session == nil {
		session, err = model2_auth_session.Create()
		session.Update(model2.Fields{
			"RemoteAddr": c.connection.GetRemoteAddr(),
			"UserAgent":  c.connection.GetUserAgent(),
		})
	}

	if session.IsLock {
		b, err := star.Send(session.LockServerUUID, model.Fields{
			"command":      "get_session_lock_state",
			"session_uuid": session.UUID,
		})

		var commandCheckSessionDetector CommandCheckSessionDetector
		if err == nil {
			json.Unmarshal(b, &commandCheckSessionDetector)
		}

		if err != nil || commandCheckSessionDetector.IsLock {
			// session.Create(c.connection.GetRemoteAddr(), c.connection.GetUserAgent())
			session, err = model2_auth_session.Create()
			session.Update(model2.Fields{
				"RemoteAddr": c.connection.GetRemoteAddr(),
				"UserAgent":  c.connection.GetUserAgent(),
			})
		}

		logger.String(string(b))
	}

	// session.Lock()
	c.connection.SetSession(session)

	sendCommandAuth := SendCommandAuth{
		Command:      "auth",
		SessionUUID:  session.UUID.String(),
		AuthMethods:  c.ctx.Config.Auth.Methods,
		IsAuth:       session.IsAuth,
		PlayerExists: false,
	}

	if session.IsAuth {

		/*
			user := model2_user.New()
			user.UUID = session.UserUUID
			user.Load()
		*/
		user, _ := model2_user.Load(session.UserUUID)
		logger.String(fmt.Sprintf("user: %+v", user))

		// check for user lock
		if user.IsLock {

			b, err := star.Send(user.LockServerUUID, model.Fields{
				"command":   "get_user_lock_state",
				"user_uuid": user.UUID.String(),
			})

			if err != nil {

			} else {

				type CommandCheckUserDetector struct {
					IsLock bool `json:"is_lock"`
				}

				var commandCheckUserDetector CommandCheckUserDetector
				json.Unmarshal(b, &commandCheckUserDetector)

				if commandCheckUserDetector.IsLock {

					_, _ = star.Send(user.LockServerUUID, model.Fields{
						"command":      "star_user_logout",
						"user_uuid":    user.UUID,
						"session_uuid": session.UUID.String(),
					})

					user.Load()
				}

			}
		}

		// user.Lock()

		if user.PlayerUUID != nil {
			sendCommandAuth.PlayerExists = true
		}

		sendCommandAuth.User = SendCommandAuthUser{
			Name:        user.Name,
			SectionName: user.SectionName,
		}
	}

	b, err := json.Marshal(sendCommandAuth)
	if err != nil {
		logger.Error(errors.New(err))
		return
	}

	c.connection.Send(string(b))
}
Example #14
0
// Process communication payload from device (via websocket. or REST)
//  {
//      "device_id" : "9dfe2a00-efe2-45f9-a84c-8afc69caf4e7",
//        "sddl" : {
//          "optional inbound bool onoff" : {}
//        },
//        "vars" : {
//            "temperature" : 38.0f;
//            "gps" : {
//                "latitude" : 38.0f;
//                "longitude" : 38.0f;
//            }
//        }
//    }
//  }
//
//  <conn> is an optional datalayer connection.  If provided, it is used.
//  Otherwise, a datalayer connection is opened by this routine.
//
//  <device> is the device that sent the communication.  If nil, then either
//  <deviceId> or, as a last resort, the payload's "device_id" will be used.
//
//  <deviceId> is a string device ID of the device that sent the communication.
//  This is ignored if <device> is not nil.  If nil, then the payload's
//  "device_id" will be used.
//
//  <secretKey> is the device's secret key. A secret key is required if
//  <device> is nil.  Either the value of <secretKey> or, as a last resort, the
//  payload's "secret_key" field will be used.
//
//  <payload> is a string containing the JSON payload.
func ProcessDeviceComm(
	cfg config.Config,
	conn datalayer.Connection,
	device datalayer.Device,
	deviceIdString string,
	secretKey string,
	payload string) ServiceResponse {
	var err error
	var out ServiceResponse
	var ok bool

	canolog.Info("ProcessDeviceComm STARTED")
	// If conn is nil, open a datalayer connection.
	if conn == nil {
		dl := cassandra_datalayer.NewDatalayer(cfg)
		conn, err = dl.Connect("canopy")
		if err != nil {
			return ServiceResponse{
				HttpCode: http.StatusInternalServerError,
				Err:      fmt.Errorf("Could not connect to database: %s", err),
				Response: `{"result" : "error", "error_type" : "could_not_connect_to_database"}`,
				Device:   nil,
			}
		}
		defer conn.Close()
	}

	// Parse JSON payload
	var payloadObj map[string]interface{}
	err = json.Unmarshal([]byte(payload), &payloadObj)
	if err != nil {
		return ServiceResponse{
			HttpCode: http.StatusBadRequest,
			Err:      fmt.Errorf("Error JSON decoding payload: %s", err),
			Response: `{"result" : "error", "error_type" : "decoding_paylaod"}`,
			Device:   nil,
		}
	}

	// Device can be provided to this routine in one of three ways:
	// 1) <device> parameter
	// 2) <deviceId> parameter
	// 3) "device_id" field in payload
	if device == nil && deviceIdString != "" {
		// Parse UUID
		uuid, err := gocql.ParseUUID(deviceIdString)
		if err != nil {
			return ServiceResponse{
				HttpCode: http.StatusBadRequest,
				Err:      fmt.Errorf("Invalid UUID %s: %s", deviceIdString, err),
				Response: `{"result" : "error", "error_type" : "device_uuid_required"}`,
				Device:   nil,
			}
		}

		// Get secret key from payload if necessary
		if secretKey == "" {
			secretKey, ok = payloadObj["secret_key"].(string)
			if !ok {
				return ServiceResponse{
					HttpCode: http.StatusBadRequest,
					Err:      fmt.Errorf("\"secret_key\" field must be string"),
					Response: `{"result" : "error", "error_type" : "bad_payload"}`,
					Device:   nil,
				}
			}
		}

		// lookup device
		device, err = conn.LookupDeviceVerifySecretKey(uuid, secretKey)
		if err != nil {
			return ServiceResponse{
				HttpCode: http.StatusInternalServerError,
				Err:      fmt.Errorf("Error looking up or verifying device: %s", err),
				Response: `{"result" : "error", "error_type" : "database_error"}`,
				Device:   nil,
			}
		}
	}

	// Is "device_id" provided in payload?
	_, ok = payloadObj["device_id"]
	if ok {
		deviceIdStringFromPayload, ok := payloadObj["device_id"].(string)
		if !ok {
			return ServiceResponse{
				HttpCode: http.StatusBadRequest,
				Err:      fmt.Errorf("\"device_id\" field must be string"),
				Response: `{"result" : "error", "error_type" : "bad_payload"}`,
				Device:   nil,
			}
		}

		// Parse UUID
		uuid, err := gocql.ParseUUID(deviceIdStringFromPayload)
		if err != nil {
			return ServiceResponse{
				HttpCode: http.StatusBadRequest,
				Err:      fmt.Errorf("Invalid UUID %s: %s", deviceIdStringFromPayload, err),
				Response: `{"result" : "error", "error_type" : "device_uuid_required"}`,
				Device:   nil,
			}
		}

		// Is <device> already set?
		// If not: set it.
		// If so: ensure consistency
		if device == nil {

			// Get secret key from payload if necessary
			if secretKey == "" {
				secretKey, ok = payloadObj["secret_key"].(string)
				if !ok {
					return ServiceResponse{
						HttpCode: http.StatusBadRequest,
						Err:      fmt.Errorf("\"secret_key\" field must be string"),
						Response: `{"result" : "error", "error_type" : "bad_payload"}`,
						Device:   nil,
					}
				}
			}

			// Lookup device
			device, err = conn.LookupDeviceVerifySecretKey(uuid, secretKey)
			if err != nil {
				return ServiceResponse{
					HttpCode: http.StatusInternalServerError,
					Err:      fmt.Errorf("Error looking up or verifying device: %s", err),
					Response: `{"result" : "error", "error_type" : "database_error"}`,
					Device:   nil,
				}
			}
		} else {
			if device.ID().String() != deviceIdStringFromPayload {
				return ServiceResponse{
					HttpCode: http.StatusBadRequest,
					Err:      fmt.Errorf("Inconsistent device ID: %s %s", device.ID().String(), deviceIdStringFromPayload),
					Response: `{"result" : "error", "error_type" : "bad_payload"}`,
					Device:   nil,
				}
			}
		}
	}

	// If device wasn't provided at all, throw error.
	if device == nil {
		return ServiceResponse{
			HttpCode: http.StatusBadRequest,
			Err:      fmt.Errorf("Device ID expected"),
			Response: `{"result" : "error", "error_type" : "bad_payload"}`,
			Device:   nil,
		}
	}
	out.Device = device

	device.UpdateLastActivityTime(nil)

	// If "sddl" is present, create new / reconfigure Cloud Variables.
	_, ok = payloadObj["sddl"]
	if ok {
		updateMap, ok := payloadObj["sddl"].(map[string]interface{})
		if !ok {
			return ServiceResponse{
				HttpCode: http.StatusBadRequest,
				Err:      fmt.Errorf("Expected object for \"sdd\" field"),
				Response: `{"result" : "error", "error_type" : "bad_payload"}`,
				Device:   nil,
			}
		}
		err = device.ExtendSDDL(updateMap)
		if err != nil {
			return ServiceResponse{
				HttpCode: http.StatusInternalServerError,
				Err:      fmt.Errorf("Error updating device's SDDL: %s", err),
				Response: `{"result" : "error", "error_type" : "database_error"}`,
				Device:   nil,
			}
		}
	}

	// If "vars" is present, update value of all Cloud Variables (creating new
	// Cloud Variables as necessary)
	doc := device.SDDLDocument()
	_, ok = payloadObj["vars"]
	canolog.Info("vars present:", ok)
	if ok {
		varsMap, ok := payloadObj["vars"].(map[string]interface{})
		if !ok {
			return ServiceResponse{
				HttpCode: http.StatusBadRequest,
				Err:      fmt.Errorf("Expected object for \"vars\" field"),
				Response: `{"result" : "error", "error_type" : "bad_payload"}`,
				Device:   nil,
			}
		}
		canolog.Info("varsMap: ", varsMap)
		for varName, value := range varsMap {
			varDef, err := doc.LookupVarDef(varName)
			// TODO: an error doesn't necessarily mean prop should be created?
			canolog.Info("Looking up property ", varName)
			if varDef == nil {
				// Property doesn't exist.  Add it.
				canolog.Info("Not found.  Add property ", varName)
				// TODO: What datatype?
				// TODO: What other parameters?
				varDef, err = doc.AddVarDef(varName, sddl.DATATYPE_FLOAT32)
				if err != nil {
					return ServiceResponse{
						HttpCode: http.StatusInternalServerError,
						Err:      fmt.Errorf("Error creating cloud variable %s: %s", varName, err),
						Response: `{"result" : "error", "error_type" : "database_error"}`,
						Device:   nil,
					}
				}

				// save modified SDDL
				// TODO: Save at the end?
				canolog.Info("SetSDDLDocument ", doc)
				err = device.SetSDDLDocument(doc)
				if err != nil {
					return ServiceResponse{
						HttpCode: http.StatusInternalServerError,
						Err:      fmt.Errorf("Error updating SDDL: %s", err),
						Response: `{"result" : "error", "error_type" : "database_error"}`,
						Device:   nil,
					}
				}
			}

			// Store property value.
			// Convert value datatype
			varVal, err := cloudvar.JsonToCloudVarValue(varDef, value)
			if err != nil {
				return ServiceResponse{
					HttpCode: http.StatusInternalServerError,
					Err:      fmt.Errorf("Error converting JSON to propertyValue: %s", err),
					Response: `{"result" : "error", "error_type" : "bad_payload"}`,
					Device:   nil,
				}
			}
			canolog.Info("InsertStample")
			err = device.InsertSample(varDef, time.Now(), varVal)
			if err != nil {
				return ServiceResponse{
					HttpCode: http.StatusInternalServerError,
					Err:      fmt.Errorf("Error inserting sample %s: %s", varName, err),
					Response: `{"result" : "error", "error_type" : "database_error"}`,
					Device:   nil,
				}
			}
		}
	}

	return ServiceResponse{
		HttpCode: http.StatusOK,
		Err:      nil,
		Response: `{"result" : "ok"}`,
		Device:   device,
	}
}
Example #15
0
func main() {
	cfg := config.NewDefaultConfig("", "", "")
	err := cfg.LoadConfig()
	if err != nil {
		fmt.Printf("Error loading config")
	}

	err = canolog.Init(".canopy-ops.log")
	if err != nil {
		fmt.Println(err)
		return
	}
	flag.Parse()
	cmd := canopy_ops.FindCommand(cmds, flag.Arg(0))
	info := canopy_ops.CommandInfo{
		CmdList: cmds,
		Cfg:     cfg,
		Args:    flag.Args(),
	}
	if cmd != nil {
		cmd.Perform(info)
	} else if flag.Arg(0) == "create-account" {
		dl := cassandra_datalayer.NewDatalayer(cfg)
		conn, _ := dl.Connect("canopy")
		conn.CreateAccount(flag.Arg(1), flag.Arg(2), flag.Arg(3))
	} else if flag.Arg(0) == "delete-account" {
		dl := cassandra_datalayer.NewDatalayer(cfg)
		conn, _ := dl.Connect("canopy")
		conn.DeleteAccount(flag.Arg(1))
	} else if flag.Arg(0) == "create-device" {
		dl := cassandra_datalayer.NewDatalayer(cfg)
		conn, _ := dl.Connect("canopy")

		account, err := conn.LookupAccount(flag.Arg(1))
		if err != nil {
			fmt.Println("Unable to lookup account ", flag.Arg(1), ":", err)
			return
		}

		device, err := conn.CreateDevice(flag.Arg(2), nil, "", datalayer.NoAccess)
		if err != nil {
			fmt.Println("Unable to create device: ", err)
			return
		}

		err = device.SetAccountAccess(account, datalayer.ReadWriteAccess, datalayer.ShareRevokeAllowed)
		if err != nil {
			fmt.Println("Unable to grant account access to device: ", err)
			return
		}
	} else if flag.Arg(0) == "list-devices" {
		dl := cassandra_datalayer.NewDatalayer(cfg)
		conn, _ := dl.Connect("canopy")

		account, err := conn.LookupAccount(flag.Arg(1))
		if err != nil {
			fmt.Println("Unable to lookup account ", flag.Arg(1), ":", err)
			return
		}

		devices, err := account.Devices().DeviceList(0, -1)
		if err != nil {
			fmt.Println("Error reading devices: ", err)
			return
		}
		for _, device := range devices {
			fmt.Printf("%s %s\n", device.ID(), device.Name())
		}

	} else if flag.Arg(0) == "gen-fake-sensor-data" {
		dl := cassandra_datalayer.NewDatalayer(cfg)
		conn, _ := dl.Connect("canopy")
		deviceId, err := gocql.ParseUUID(flag.Arg(1))
		if err != nil {
			fmt.Println("Error parsing UUID: ", flag.Arg(1), ":", err)
			return
		}
		_, err = conn.LookupDevice(deviceId)
		if err != nil {
			fmt.Println("Device not found: ", flag.Arg(1), ":", err)
			return
		}
		for i := 0; i < 100; i++ {
			//val := float64(i % 16);
			//t := time.Now().Add(time.Duration(-i)*time.Second)
			//err = device.InsertSensorSample(flag.Arg(2), t, val)
			//if err != nil {
			fmt.Println("Error inserting sample: ", err)
			//}
		}
	} else if flag.Arg(0) == "clear-sensor-data" {
		dl := cassandra_datalayer.NewDatalayer(cfg)
		conn, _ := dl.Connect("canopy")
		conn.ClearSensorData()

	} else if flag.Arg(0) == "test-email" {
		mailer, err := mail.NewMailClient(cfg)
		if err != nil {
			fmt.Println("Error initializing mail client: ", err)
			return
		}
		mail := mailer.NewMail()
		err = mail.AddTo(flag.Arg(1), "Customer")
		if err != nil {
			fmt.Println("Invalid recipient: ", flag.Arg(1), err)
			return
		}
		mail.SetSubject("Test email from Canopy")
		mail.SetHTML("<b>Canopy Rulez</b>")
		mail.SetFrom("*****@*****.**", "The Canopy Team")
		err = mailer.Send(mail)
		if err != nil {
			fmt.Println("Error sending email:", err)
			return
		}
		fmt.Println("Email sent.")
	} else if flag.Arg(0) == "migrate-db" {
		startVersion := flag.Arg(1)
		if startVersion == "" {
			fmt.Println("<startVersion> required")
			return
		}
		endVersion := flag.Arg(2)
		if endVersion == "" {
			fmt.Println("<endVersion> required")
			return
		}
		dl := cassandra_datalayer.NewDatalayer(cfg)
		err := dl.MigrateDB("canopy", startVersion, endVersion)
		if err != nil {
			fmt.Println(err.Error())
		}
	} else if len(flag.Args()) == 0 {
		cmds[0].Perform(info)
	} else {
		fmt.Println("Unknown command '" + flag.Arg(0) + "'.  See 'canopy-ops help'.")
	}
}
func GET__api__device__id__var(info *RestRequestInfo, sideEffect *RestSideEffects) (map[string]interface{}, RestError) {
	deviceIdString := info.URLVars["id"]
	sensorName := info.URLVars["var"]
	authorized := false
	var device datalayer.Device

	uuid, err := gocql.ParseUUID(deviceIdString)
	if err != nil {
		return nil, URLNotFoundError()
	}

	//if info.Config.OptAllowAnonDevices() && device.PublicAccessLevel() > datalayer.NoAccess {
	device, err = info.Conn.LookupDevice(uuid)
	if err != nil {
		// TODO: What errors to return here?
		return nil, InternalServerError("Device lookup failed")
	}
	authorized = true
	//} else {
	// TODO: fix anon devices
	if info.Account == nil {
		return nil, NotLoggedInError()
	}

	device, err = info.Account.Device(uuid)
	if err != nil {
		// TODO: What errors to return here?
		return nil, InternalServerError("Device lookup failed")
	}

	authorized = true
	//}

	if !authorized {
		// TODO: What is the correct error for this?
		return nil, URLNotFoundError()
	}

	doc := device.SDDLDocument()
	if doc == nil {
		return nil, URLNotFoundError()
	}

	varDef, err := doc.LookupVarDef(sensorName)
	if err != nil {
		return nil, URLNotFoundError()
	}

	samples, err := device.HistoricData(varDef, time.Now(), time.Now().Add(-59*time.Minute), time.Now())
	if err != nil {
		return nil, InternalServerError("Could not obtain sample data: " + err.Error())
	}

	// Convert samples to JSON
	out := map[string]interface{}{}
	out["result"] = "ok"
	out["samples"] = []interface{}{}
	for _, sample := range samples {
		out["samples"] = append(out["samples"].([]interface{}), map[string]interface{}{
			"t": sample.Timestamp.Format(time.RFC3339),
			"v": sample.Value,
		})
	}

	return out, nil
}