An app written in GoLang to find people using location services on smartphones.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

257 lines
8.1 KiB

package main
import (
"net/http"
"html/template"
"log"
"encoding/json"
"io/ioutil"
"regexp"
"github.com/go-redis/redis"
"time"
"strconv"
"crypto/rand"
)
type location_set struct {
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
Id string `json:"id"`
Key string `json:"key"`
}
type item_key struct {
Id string
Key string
}
func setlocation(w http.ResponseWriter, r *http.Request){
item := item_key{r.FormValue("id"), r.FormValue("key")}
t, err := template.ParseFiles("setlocation.html")
if err != nil {
log.Print("template parsing error: ", err)
}
err = t.Execute(w, item)
if err != nil {
log.Print("template executing error: ", err)
}
}
func getlocation(w http.ResponseWriter, r *http.Request){
item := item_key{r.FormValue("id"), r.FormValue("key")}
t, err := template.ParseFiles("getlocation.html")
if err != nil {
log.Print("template parsing error: ", err)
}
err = t.Execute(w, item)
if err != nil {
log.Print("template executing error: ", err)
}
}
func managelocations(w http.ResponseWriter, r *http.Request){
t, err := template.ParseFiles("managelocations.html")
if err != nil {
log.Print("template parsing error: ", err)
}
err = t.Execute(w, nil)
if err != nil {
log.Print("template executing error: ", err)
}
}
func api_location(w http.ResponseWriter, r *http.Request){
switch r.Method {
case "GET":
id := r.FormValue("id")
key := r.FormValue("key")
id_exists := check_item_key(id, key)
if id_exists != true {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(http.StatusText(http.StatusNotFound) + "\n"))
return
}
latitude, latitude_err := read_key("latitude-" + id)
if latitude_err != true {
w.WriteHeader(http.StatusNoContent)
w.Write([]byte(http.StatusText(http.StatusNoContent) + "\n"))
return
}
longitude, longitude_err := read_key("longitude-" + id)
if longitude_err != true {
w.WriteHeader(http.StatusNoContent)
w.Write([]byte(http.StatusText(http.StatusNoContent) + "\n"))
return
}
output, marshal_err := json.Marshal(map[string]float64{"latitude": latitude, "longitude": longitude})
if marshal_err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
return
}
w.Write([]byte(output))
return
case "POST":
body, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(http.StatusText(http.StatusBadRequest) + "\n"))
return
}
var location_data location_set
location_err := json.Unmarshal(body, &location_data)
if location_err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(http.StatusText(http.StatusBadRequest) + "\n"))
return
}
id_exists := check_item_key(location_data.Id, location_data.Key)
if id_exists != true {
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(http.StatusText(http.StatusNotFound) + "\n"))
return
}
latitude_written := write_key("latitude-" + location_data.Id, location_data.Latitude)
if latitude_written != true {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
return
}
longitude_written := write_key("longitude-" + location_data.Id, location_data.Longitude)
if longitude_written != true {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
return
}
w.WriteHeader(http.StatusCreated)
w.Write([]byte(http.StatusText(http.StatusCreated) + "\n"))
return
default:
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte(http.StatusText(http.StatusNotImplemented) + "\n"))
}
}
func api_createid(w http.ResponseWriter, r *http.Request){
switch r.Method {
case "GET":
id, id_err := genrandomstring(10)
if id_err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
return
}
key, key_err := genrandomstring(32)
if key_err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
return
}
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
_, err := client.Get("key-" + id).Result()
if err == nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
return
}
writekey_err := client.Set("key-" + id, key, 30 * time.Minute).Err()
if writekey_err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
return
}
output, marshal_err := json.Marshal(map[string]string{"id": id, "key": key})
if marshal_err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(http.StatusText(http.StatusInternalServerError) + "\n"))
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(output))
return
default:
w.WriteHeader(http.StatusNotImplemented)
w.Write([]byte(http.StatusText(http.StatusNotImplemented) + "\n"))
}
}
func check_item_key(id string, key string) bool {
id_safe, _ := regexp.MatchString(`^[a-zA-Z0-9]{10}$`, id)
if id_safe != true {
return false
}
key_safe, _ := regexp.MatchString(`^[a-zA-Z0-9]{32}$`, key)
if key_safe != true {
return false
}
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
item, err := client.Get("key-" + id).Result()
if err != nil {
return false
}
if key != item {
return false
}
return true
}
func write_key(id string, item float64) bool {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
err := client.Set(id, item, 30 * time.Minute).Err()
if err != nil {
return false
}
return true
}
func read_key(id string) (float64, bool) {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
item, err := client.Get(id).Result()
if err != nil {
return 0, false
}
item_float, conv_err := strconv.ParseFloat(item, 64)
if conv_err != nil {
return 0, false
}
return item_float, true
}
func genrandomstring(length int) (string, error) {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
output := make([]byte, length)
_, err := rand.Read(output)
if err != nil {
return "", err
}
for i, b := range output {
output[i] = charset[b%byte(len(charset))]
}
return string(output), nil
}
func main() {
http.HandleFunc("/managelocations.html", managelocations)
http.HandleFunc("/setlocation.html", setlocation)
http.HandleFunc("/getlocation.html", getlocation)
http.HandleFunc("/api/createitem", api_createid)
http.HandleFunc("/api/location", api_location)
http.ListenAndServe("127.0.0.1:8080", nil)
}