package admin import ( "encoding/json" "errors" "fmt" "log" "net" "net/http" "strconv" "time" "git.maze.io/maze/styx/dataset" ) func (a *Admin) apiClients(w http.ResponseWriter, r *http.Request) { clients, err := a.Storage.Clients() if err != nil { a.handleAPIError(w, r, err) return } a.jsonResponse(w, r, clients) } func (a *Admin) apiClient(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { a.handleAPIError(w, r, err) return } client, err := a.Storage.ClientByID(id) if err != nil { a.handleAPIError(w, r, err) return } a.jsonResponse(w, r, client) } func (a *Admin) apiClientCreate(w http.ResponseWriter, r *http.Request) { var request struct { dataset.Client Groups []int64 `json:"groups"` ID int64 `json:"id"` // mask, not used CreatedAt time.Time `json:"created_at"` // mask, not used UpdatedAt time.Time `json:"updated_at"` // mask, not used } if err := json.NewDecoder(r.Body).Decode(&request); err != nil { a.handleAPIError(w, r, err) return } if err := a.verifyClient(&request.Client); err != nil { a.handleAPIError(w, r, err) return } var groups []dataset.Group for _, id := range request.Groups { group, err := a.Storage.GroupByID(id) if err != nil { a.handleAPIError(w, r, err) return } groups = append(groups, group) } request.Client.Groups = groups if err := a.Storage.SaveClient(&request.Client); err != nil { a.handleAPIError(w, r, err) return } a.jsonResponse(w, r, request.Client) } func (a *Admin) apiClientUpdate(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { a.handleAPIError(w, r, err) return } client, err := a.Storage.ClientByID(id) if err != nil { a.handleAPIError(w, r, err) return } log.Printf("updating: %#+v", client) var request struct { dataset.Client Groups []int64 `json:"groups"` } if err := json.NewDecoder(r.Body).Decode(&request); err != nil { a.handleAPIError(w, r, err) return } if err := a.verifyClient(&request.Client); err != nil { a.handleAPIError(w, r, err) return } client.IP = request.Client.IP client.Mask = request.Client.Mask client.Description = request.Client.Description client.Groups = client.Groups[:0] for _, id := range request.Groups { group, err := a.Storage.GroupByID(id) if err != nil { a.handleAPIError(w, r, err) return } client.Groups = append(client.Groups, group) } if err := a.Storage.SaveClient(&client); err != nil { a.handleAPIError(w, r, err) return } a.jsonResponse(w, r, client) } func (a *Admin) apiClientDelete(w http.ResponseWriter, r *http.Request) { id, err := strconv.ParseInt(r.PathValue("id"), 10, 64) if err != nil { a.handleAPIError(w, r, err) return } client, err := a.Storage.ClientByID(id) if err != nil { a.handleAPIError(w, r, err) return } if err = a.Storage.DeleteClient(client); err != nil { a.handleAPIError(w, r, err) return } a.jsonResponse(w, r, nil) } func (a *Admin) verifyClient(c *dataset.Client) (err error) { ip := net.ParseIP(c.IP) switch c.Network { case "ipv4": if ip.To4() == nil { return apiError{Err: errors.New("invalid IPv4 address")} } if c.Mask == 0 { c.Mask = 32 // one IP } if c.Mask <= 0 || c.Mask > 32 { return apiError{Err: errors.New("mask can't be zero")} } c.IP = ip.Mask(net.CIDRMask(int(c.Mask), 32)).String() case "ipv6": if ip.To16() == nil { return apiError{Err: errors.New("invalid IPv6 address")} } if c.Mask == 0 { c.Mask = 128 // one IP } if c.Mask <= 0 || c.Mask > 128 { return apiError{Err: errors.New("mask can't be zero")} } c.IP = ip.Mask(net.CIDRMask(int(c.Mask), 128)).String() case "": if ip.To4() != nil { c.Network = "ipv4" } else if ip.To16() != nil { c.Network = "ipv6" } else { return apiError{Err: errors.New("invalid IP address")} } return a.verifyClient(c) default: return apiError{Err: fmt.Errorf("invalid network %q", c.Network)} } return }