mirror of
https://github.com/MirageNetwork/MirageServer.git
synced 2025-10-07 01:02:53 +08:00
646 lines
21 KiB
Go
646 lines
21 KiB
Go
package controller
|
||
|
||
import (
|
||
_ "embed"
|
||
"encoding/json"
|
||
"net/http"
|
||
"net/netip"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/rs/zerolog/log"
|
||
)
|
||
|
||
type machineData struct {
|
||
Address []string `json:"addresses"`
|
||
AllowedIPs []string `json:"allowedIPs"`
|
||
ExtraIPs []string `json:"extraIPs"`
|
||
AdvertisedIPs []string `json:"advertisedIPs"`
|
||
HasSubnets bool `json:"hasSubnets"`
|
||
AdvertisedExitNode bool `json:"advertisedExitNode"`
|
||
AllowedExitNode bool `json:"allowedExitNode"`
|
||
HasExitNode bool `json:"hasExitNode"` //未实现
|
||
AllowedTags []string `json:"allowedTags"` //未实现
|
||
InvalidTags []string `json:"invalidTags"` //未实现
|
||
HasTags bool `json:"hasTags"` //未实现
|
||
Endpoints []string `json:"endpoints"`
|
||
Derp string `json:"derp"` //未实现
|
||
IpnVersion string `json:"ipnVersion"` //未实现
|
||
Os string `json:"os"` //未实现
|
||
Name string `json:"name"` //未实现
|
||
Fqdn string `json:"fqdn"` //未实现
|
||
Domain string `json:"domain"` //未实现
|
||
Created string `json:"created"` //未实现
|
||
Hostname string `json:"hostname"` //未实现
|
||
MachineKey string `json:"machineKey"` //未实现
|
||
NodeKey string `json:"nodeKey"` //未实现
|
||
Id string `json:"id"` //未实现
|
||
StableId string `json:"stableId"` //未实现
|
||
DisplayNodeKey string `json:"displayNodeKey"` //未实现
|
||
LogID string `json:"logID"` //未实现
|
||
User string `json:"user"` //未实现
|
||
Creator string `json:"creator"` //未实现
|
||
Expires string `json:"expires"`
|
||
NeverExpires bool `json:"neverExpires"`
|
||
Authorized bool `json:"authorized"` //未实现
|
||
IsExternal bool `json:"isExternal"` //未实现
|
||
BrokenIPForwarding bool `json:"brokenIPForwarding"` //未实现
|
||
IsEphemeral bool `json:"isEphemeral"` //未实现
|
||
AvailableUpdateVersion string `json:"availableUpdateVersion"` //未实现
|
||
LastSeen string `json:"lastSeen"` //未实现
|
||
ConnectedToControl bool `json:"connectedToControl"` //未实现
|
||
AutomaticNameMode bool `json:"automaticNameMode"`
|
||
TailnetLockKey string `json:"tailnetLockKey"` //未实现
|
||
ShareID string `json:"shareID"` //未实现
|
||
AcceptedShareCount int `json:"acceptedShareCount"` //未实现
|
||
ParsedLinuxVersion string `json:"parsedLinuxVersion"` //未实现
|
||
}
|
||
|
||
type machineItem struct {
|
||
Name string `json:"name"` //done
|
||
User string `json:"user"` //done
|
||
UserNameHead string `json:"usernamehead"` // TODO
|
||
Addresses []string `json:"addresses"` //done
|
||
Os string `json:"os"` //done
|
||
Hostname string `json:"hostname"` //done
|
||
IpnVersion string `json:"ipnVersion"` //done
|
||
ConnectedToControl bool `json:"connectedToControl"` //done
|
||
LastSeen string `json:"lastSeen"` //done
|
||
Created string `json:"created"` //done
|
||
|
||
IsExternal bool `json:"isExternal"`
|
||
IsEphemeral bool `json:"isEphemeral"`
|
||
IsSharedOut bool `json:"issharedout"`
|
||
NeverExpires bool `json:"neverExpires"` //done
|
||
|
||
AllowedIPs []string `json:"allowedIPs"`
|
||
ExtraIPs []string `json:"extraIPs"`
|
||
AdvertisedIPs []string `json:"advertisedIPs"`
|
||
HasSubnets bool `json:"hasSubnets"`
|
||
AdvertisedExitNode bool `json:"advertisedExitNode"`
|
||
AllowedExitNode bool `json:"allowedExitNode"`
|
||
AllowedTags []string `json:"allowedTags"`
|
||
InvalidTags []string `json:"invalidTags"`
|
||
HasTags bool `json:"hasTags"`
|
||
|
||
Varies bool `json:"varies"`
|
||
HairPinning bool `json:"hairpinning"`
|
||
CanIPv6 bool `json:"ipv6en"`
|
||
CanUDP bool `json:"udpen"`
|
||
CanUPnP bool `json:"upnpen"`
|
||
CanPCP bool `json:"pcpen"`
|
||
CanPMP bool `json:"pmpen"`
|
||
|
||
ExpiryDesc string `json:"expirydesc"`
|
||
|
||
Endpoints []string `json:"endpoints"`
|
||
DERPs map[string]int `json:"derps"`
|
||
PrefferDERP string `json:"usederp"`
|
||
AutomaticNameMode bool `json:"automaticNameMode"`
|
||
}
|
||
|
||
// 控制台获取设备信息列表的API
|
||
func (h *Mirage) ConsoleMachinesAPI(
|
||
writer http.ResponseWriter,
|
||
req *http.Request,
|
||
) {
|
||
controlCodeCookie, err := req.Cookie("miragecontrol")
|
||
if err != nil {
|
||
errRes := adminTemplateConfig{ErrorMsg: "Token不存在"}
|
||
err = json.NewEncoder(writer).Encode(&errRes)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
|
||
controlCode := controlCodeCookie.Value
|
||
controlCodeC, controlCodeExpiration, ok := h.controlCodeCache.GetWithExpiration(controlCode)
|
||
if !ok || controlCodeExpiration.Compare(time.Now()) != 1 {
|
||
errRes := adminTemplateConfig{ErrorMsg: "解析Token失败"}
|
||
err = json.NewEncoder(writer).Encode(&errRes)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
controlCodeItem := controlCodeC.(ControlCacheItem)
|
||
user, err := h.GetUserByID(controlCodeItem.uid)
|
||
if err != nil {
|
||
errRes := adminTemplateConfig{ErrorMsg: "提取用户信息失败"}
|
||
err = json.NewEncoder(writer).Encode(&errRes)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
|
||
OrgMachines, err := h.ListMachinesByOrgID(user.OrganizationID)
|
||
if err != nil {
|
||
errRes := adminTemplateConfig{ErrorMsg: "查询用户节点列表失败"}
|
||
err = json.NewEncoder(writer).Encode(&errRes)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
|
||
mlist := make(map[string]machineItem)
|
||
for _, machine := range OrgMachines {
|
||
tz, _ := time.LoadLocation("Asia/Shanghai")
|
||
tmpMachine := machineItem{
|
||
Name: machine.GivenName,
|
||
User: machine.User.Name,
|
||
UserNameHead: string([]rune(machine.User.Display_Name)[0]),
|
||
Os: machine.HostInfo.OS,
|
||
Hostname: machine.HostInfo.Hostname,
|
||
IpnVersion: machine.HostInfo.IPNVersion,
|
||
Created: machine.CreatedAt.In(tz).Format("2006年01月02日 15:04:05"),
|
||
LastSeen: machine.LastSeen.In(tz).Format("2006年01月02日 15:04:05"),
|
||
ConnectedToControl: machine.isOnline(),
|
||
AllowedTags: machine.ForcedTags,
|
||
InvalidTags: []string{},
|
||
HasTags: machine.ForcedTags != nil && len(machine.ForcedTags) > 0,
|
||
|
||
IsEphemeral: machine.isEphemeral(),
|
||
NeverExpires: *machine.Expiry == time.Time{},
|
||
|
||
Varies: machine.HostInfo.NetInfo != nil && machine.HostInfo.NetInfo.MappingVariesByDestIP.EqualBool(true),
|
||
HairPinning: machine.HostInfo.NetInfo != nil && machine.HostInfo.NetInfo.HairPinning.EqualBool(true),
|
||
CanIPv6: machine.HostInfo.NetInfo != nil && machine.HostInfo.NetInfo.WorkingIPv6.EqualBool(true),
|
||
CanUDP: machine.HostInfo.NetInfo != nil && machine.HostInfo.NetInfo.WorkingUDP.EqualBool(true),
|
||
CanUPnP: machine.HostInfo.NetInfo != nil && machine.HostInfo.NetInfo.UPnP.EqualBool(true),
|
||
CanPCP: machine.HostInfo.NetInfo != nil && machine.HostInfo.NetInfo.PCP.EqualBool(true),
|
||
CanPMP: machine.HostInfo.NetInfo != nil && machine.HostInfo.NetInfo.PMP.EqualBool(true),
|
||
Endpoints: machine.Endpoints,
|
||
AutomaticNameMode: machine.AutoGenName,
|
||
}
|
||
// 处理标签部分
|
||
if machine.ForcedTags != nil && len(machine.ForcedTags) > 0 {
|
||
org, err := h.GetOrgnaizationByID(user.OrganizationID)
|
||
if err != nil {
|
||
errRes := adminTemplateConfig{ErrorMsg: "查询设备组织失败"}
|
||
err = json.NewEncoder(writer).Encode(&errRes)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
for _, tag := range machine.ForcedTags {
|
||
if _, ok := org.AclPolicy.TagOwners[tag]; ok {
|
||
tmpMachine.AllowedTags = append(tmpMachine.AllowedTags, tag)
|
||
} else {
|
||
tmpMachine.InvalidTags = append(tmpMachine.InvalidTags, tag)
|
||
}
|
||
}
|
||
}
|
||
// 处理路由部分
|
||
machineRoutes, err := h.GetMachineRoutes(&machine)
|
||
if err != nil {
|
||
errRes := adminTemplateConfig{ErrorMsg: "查询设备路由失败"}
|
||
err = json.NewEncoder(writer).Encode(&errRes)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
for _, route := range machineRoutes {
|
||
if route.isExitRoute() {
|
||
if route.Advertised {
|
||
tmpMachine.AdvertisedExitNode = true
|
||
if route.Enabled {
|
||
tmpMachine.AllowedExitNode = true
|
||
}
|
||
}
|
||
} else {
|
||
if route.Advertised {
|
||
tmpMachine.HasSubnets = true
|
||
routeV := netip.Prefix(route.Prefix).String()
|
||
if err != nil {
|
||
errRes := adminTemplateConfig{ErrorMsg: "子网路由地址转换失败"}
|
||
err = json.NewEncoder(writer).Encode(&errRes)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
tmpMachine.AdvertisedIPs = append(tmpMachine.AdvertisedIPs, routeV)
|
||
if route.Enabled {
|
||
tmpMachine.AllowedIPs = append(tmpMachine.AllowedIPs, routeV)
|
||
} else {
|
||
tmpMachine.ExtraIPs = append(tmpMachine.ExtraIPs, routeV)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if machine.HostInfo.NetInfo != nil && machine.HostInfo.NetInfo.PreferredDERP != 0 {
|
||
tmpMachine.DERPs = make(map[string]int)
|
||
for derpname, latency := range machine.HostInfo.NetInfo.DERPLatency {
|
||
ipver := strings.Split(derpname, "-")[1]
|
||
derpname = strings.Split(derpname, "-")[0]
|
||
if ipver == "v4" {
|
||
if peerlatency, ok := machine.HostInfo.NetInfo.DERPLatency[derpname+"-v6"]; ok {
|
||
if latency < peerlatency {
|
||
tmpMachine.DERPs[derpname] = int(latency * 1000)
|
||
}
|
||
} else {
|
||
tmpMachine.DERPs[derpname] = int(latency * 1000)
|
||
}
|
||
} else if ipver == "v6" {
|
||
if peerlatency, ok := machine.HostInfo.NetInfo.DERPLatency[derpname+"-v4"]; ok {
|
||
if latency < peerlatency {
|
||
tmpMachine.DERPs[derpname] = int(latency * 1000)
|
||
}
|
||
} else {
|
||
tmpMachine.DERPs[derpname] = int(latency * 1000)
|
||
}
|
||
} else {
|
||
tmpMachine.DERPs[derpname] = int(latency * 1000)
|
||
}
|
||
}
|
||
tmpMachine.PrefferDERP = strconv.Itoa(machine.HostInfo.NetInfo.PreferredDERP)
|
||
} else {
|
||
tmpMachine.PrefferDERP = "x"
|
||
tmpMachine.DERPs = nil
|
||
}
|
||
if !tmpMachine.NeverExpires {
|
||
ExpiryDuration := machine.Expiry.Sub(time.Now())
|
||
tmpMachine.ExpiryDesc = convExpiryToStr(ExpiryDuration)
|
||
}
|
||
if machine.IPAddresses[0].Is4() {
|
||
tmpMachine.Addresses = []string{
|
||
machine.IPAddresses[0].String(),
|
||
machine.IPAddresses[1].String()}
|
||
} else if machine.IPAddresses[1].Is4() {
|
||
tmpMachine.Addresses = []string{
|
||
machine.IPAddresses[1].String(),
|
||
machine.IPAddresses[0].String()}
|
||
}
|
||
mlist[strconv.FormatInt(machine.ID, 10)] = tmpMachine
|
||
}
|
||
|
||
renderData := adminTemplateConfig{
|
||
Basedomain: user.Organization.MagicDnsDomain,
|
||
MList: mlist,
|
||
}
|
||
|
||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
writer.WriteHeader(http.StatusOK)
|
||
err = json.NewEncoder(writer).Encode(&renderData)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
}
|
||
|
||
func (h *Mirage) ConsoleMachinesUpdateAPI(
|
||
writer http.ResponseWriter,
|
||
req *http.Request,
|
||
) {
|
||
user := h.verifyTokenIDandGetUser(writer, req)
|
||
if user.CheckEmpty() {
|
||
h.doAPIResponse(writer, "用户信息核对失败", nil)
|
||
return
|
||
}
|
||
err := req.ParseForm()
|
||
if err != nil {
|
||
h.doAPIResponse(writer, "用户请求解析失败:"+err.Error(), nil)
|
||
return
|
||
}
|
||
reqData := make(map[string]interface{})
|
||
json.NewDecoder(req.Body).Decode(&reqData)
|
||
reqMID, ok := reqData["mid"].(string)
|
||
if !ok {
|
||
h.doAPIResponse(writer, "用户请求mid解析失败", nil)
|
||
return
|
||
}
|
||
MachineID, err := strconv.ParseInt(reqMID, 0, 64)
|
||
if err != nil {
|
||
h.doAPIResponse(writer, "用户请求mid处理失败", nil)
|
||
return
|
||
}
|
||
toUpdateMachine, err := h.GetMachineByID(MachineID)
|
||
if err != nil {
|
||
h.doAPIResponse(writer, "查询用户设备失败", nil)
|
||
return
|
||
}
|
||
if toUpdateMachine.User.ID != user.ID {
|
||
h.doAPIResponse(writer, "用户没有该权限", nil)
|
||
return
|
||
}
|
||
reqState, ok := reqData["state"].(string)
|
||
if !ok {
|
||
h.doAPIResponse(writer, "用户请求state解析失败", nil)
|
||
return
|
||
}
|
||
|
||
switch reqState {
|
||
case "set-expires": //切换密钥永不过期设置
|
||
msg, err := h.setMachineExpiry(toUpdateMachine)
|
||
if err != nil {
|
||
h.doAPIResponse(writer, msg, nil)
|
||
} else {
|
||
resData := machineData{
|
||
NeverExpires: *toUpdateMachine.Expiry == time.Time{},
|
||
Expires: msg,
|
||
}
|
||
h.doAPIResponse(writer, "", resData)
|
||
}
|
||
case "rename-node": //设置设备名称
|
||
newName := reqData["nodeName"].(string)
|
||
msg, _, err := h.setMachineName(toUpdateMachine, newName)
|
||
if err != nil {
|
||
h.doAPIResponse(writer, msg, nil)
|
||
} else {
|
||
resData := machineData{
|
||
AutomaticNameMode: toUpdateMachine.AutoGenName,
|
||
Name: toUpdateMachine.GivenName,
|
||
Hostname: toUpdateMachine.Hostname,
|
||
NeverExpires: *toUpdateMachine.Expiry == time.Time{},
|
||
Expires: msg,
|
||
}
|
||
h.doAPIResponse(writer, "", resData)
|
||
}
|
||
case "set-route-settings": //设置子网转发及出口节点
|
||
allowedIPsInterface := reqData["allowedIPs"].([]interface{})
|
||
allowExitNode := reqData["allowedExitNode"].(bool)
|
||
|
||
allowedIPs := new([]string)
|
||
for _, ip := range allowedIPsInterface {
|
||
*allowedIPs = append(*allowedIPs, ip.(string))
|
||
}
|
||
|
||
msg, err := h.setMachineSubnet(toUpdateMachine, allowExitNode, *allowedIPs)
|
||
if err != nil {
|
||
h.doAPIResponse(writer, msg, nil)
|
||
return
|
||
} else {
|
||
resData := machineData{
|
||
AutomaticNameMode: toUpdateMachine.AutoGenName,
|
||
Name: toUpdateMachine.GivenName,
|
||
Hostname: toUpdateMachine.Hostname,
|
||
NeverExpires: *toUpdateMachine.Expiry == time.Time{},
|
||
Expires: msg,
|
||
}
|
||
machineRoutes, err := h.GetMachineRoutes(toUpdateMachine)
|
||
if err != nil {
|
||
h.doAPIResponse(writer, "查询设备路由失败", nil)
|
||
return
|
||
}
|
||
for _, route := range machineRoutes {
|
||
if route.isExitRoute() {
|
||
if route.Advertised {
|
||
resData.AdvertisedExitNode = true
|
||
if route.Enabled {
|
||
resData.AllowedExitNode = true
|
||
}
|
||
}
|
||
} else {
|
||
if route.Advertised {
|
||
resData.HasSubnets = true
|
||
routeV := netip.Prefix(route.Prefix).String()
|
||
if err != nil {
|
||
h.doAPIResponse(writer, "子网路由地址转换失败", nil)
|
||
return
|
||
}
|
||
resData.AdvertisedIPs = append(resData.AdvertisedIPs, routeV)
|
||
if route.Enabled {
|
||
resData.AllowedIPs = append(resData.AllowedIPs, routeV)
|
||
} else {
|
||
resData.ExtraIPs = append(resData.ExtraIPs, routeV)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
h.doAPIResponse(writer, "", resData)
|
||
}
|
||
case "set-tags": //设置设备标签
|
||
reqTags := reqData["tags"].([]interface{})
|
||
setTags := make([]string, len(reqTags))
|
||
for i, tag := range reqTags {
|
||
setTags[i] = tag.(string)
|
||
}
|
||
msg, err := h.setMachineTags(toUpdateMachine, setTags)
|
||
if err != nil {
|
||
h.doAPIResponse(writer, msg, nil)
|
||
} else {
|
||
invalidTags := []string{}
|
||
allowedTags := []string{}
|
||
org, err := h.GetOrgnaizationByID(user.OrganizationID)
|
||
if err != nil {
|
||
h.doAPIResponse(writer, msg, nil)
|
||
}
|
||
for _, tag := range setTags {
|
||
if _, ok := org.AclPolicy.TagOwners[tag]; ok {
|
||
allowedTags = append(allowedTags, tag)
|
||
} else {
|
||
invalidTags = append(invalidTags, tag)
|
||
}
|
||
}
|
||
resData := machineData{
|
||
AutomaticNameMode: toUpdateMachine.AutoGenName,
|
||
Name: toUpdateMachine.GivenName,
|
||
Hostname: toUpdateMachine.Hostname,
|
||
NeverExpires: *toUpdateMachine.Expiry == time.Time{},
|
||
Expires: msg,
|
||
HasTags: setTags != nil && len(setTags) > 0,
|
||
AllowedTags: allowedTags,
|
||
InvalidTags: invalidTags,
|
||
}
|
||
h.doAPIResponse(writer, "", resData)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 删除设备API
|
||
type removeMachineRes struct {
|
||
Status string `json:"status"`
|
||
ErrMsg string `json:"errmsg"`
|
||
}
|
||
|
||
func (h *Mirage) ConsoleRemoveMachineAPI(
|
||
writer http.ResponseWriter,
|
||
req *http.Request,
|
||
) {
|
||
user := h.verifyTokenIDandGetUser(writer, req)
|
||
resData := removeMachineRes{}
|
||
if user.CheckEmpty() {
|
||
resData.Status = "Error"
|
||
resData.ErrMsg = "用户信息核对失败"
|
||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
writer.WriteHeader(http.StatusOK)
|
||
err := json.NewEncoder(writer).Encode(&resData)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
UserMachines, err := h.ListMachinesByUser(user.ID)
|
||
if err != nil {
|
||
resData.Status = "Error"
|
||
resData.ErrMsg = "用户设备检索失败"
|
||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
writer.WriteHeader(http.StatusOK)
|
||
err := json.NewEncoder(writer).Encode(&resData)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
err = req.ParseForm()
|
||
if err != nil {
|
||
resData.Status = "Error"
|
||
resData.ErrMsg = "用户请求解析失败"
|
||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
writer.WriteHeader(http.StatusOK)
|
||
err := json.NewEncoder(writer).Encode(&resData)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
reqData := make(map[string]string)
|
||
json.NewDecoder(req.Body).Decode(&reqData)
|
||
wantRemoveID := reqData["mid"]
|
||
for _, machine := range UserMachines {
|
||
if strconv.FormatInt(machine.ID, 10) == wantRemoveID {
|
||
err = h.HardDeleteMachine(&machine)
|
||
if err != nil {
|
||
resData.Status = "Error"
|
||
resData.ErrMsg = "用户设备删除失败"
|
||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
writer.WriteHeader(http.StatusOK)
|
||
err := json.NewEncoder(writer).Encode(&resData)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
resData.Status = "OK"
|
||
resData.ErrMsg = "用户设备成功删除"
|
||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
writer.WriteHeader(http.StatusOK)
|
||
err := json.NewEncoder(writer).Encode(&resData)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
return
|
||
}
|
||
}
|
||
resData.Status = "Error"
|
||
resData.ErrMsg = "未找到目标设备"
|
||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||
writer.WriteHeader(http.StatusOK)
|
||
err = json.NewEncoder(writer).Encode(&resData)
|
||
if err != nil {
|
||
log.Error().
|
||
Caller().
|
||
Err(err).
|
||
Msg("Failed to write response")
|
||
}
|
||
}
|
||
|
||
// 切换设备密钥是否禁用过期
|
||
func (h *Mirage) setMachineExpiry(machine *Machine) (string, error) {
|
||
if (*machine.Expiry != time.Time{}) {
|
||
err := h.RefreshMachine(machine, time.Time{})
|
||
if err != nil {
|
||
return "设备密钥过期禁用失败", err
|
||
} else {
|
||
return "", err
|
||
}
|
||
} else {
|
||
expiryDuration := time.Hour * 24 * time.Duration(machine.User.Organization.ExpiryDuration)
|
||
newExpiry := time.Now().Add(expiryDuration)
|
||
err := h.RefreshMachine(machine, newExpiry)
|
||
if err != nil {
|
||
return "设备密钥过期启用失败", err
|
||
} else {
|
||
return convExpiryToStr(expiryDuration), nil
|
||
}
|
||
}
|
||
}
|
||
|
||
// 三个返回值:msg、nowName、err
|
||
func (h *Mirage) setMachineName(machine *Machine, newName string) (string, string, error) {
|
||
newGiveName, err := h.setAutoGenName(machine, newName)
|
||
if err != nil {
|
||
return "设置主机名失败", "", err
|
||
}
|
||
return "", newGiveName, nil
|
||
}
|
||
|
||
func (h *Mirage) setMachineTags(machine *Machine, tags []string) (string, error) {
|
||
err := h.SetTags(machine, tags)
|
||
if err != nil {
|
||
return "设置设备标签失败", err
|
||
}
|
||
return "", nil
|
||
}
|
||
|
||
func (h *Mirage) setMachineSubnet(machine *Machine, ExitNodeEnable bool, allowedIPs []string) (string, error) {
|
||
machineRoutes, err := h.GetMachineRoutes(machine)
|
||
if err != nil {
|
||
return "获取设备路由设置失败", err
|
||
}
|
||
for _, r := range machineRoutes {
|
||
if r.isExitRoute() {
|
||
if ExitNodeEnable {
|
||
err = h.EnableRoute(uint64(r.ID))
|
||
} else {
|
||
err = h.DisableRoute(uint64(r.ID))
|
||
}
|
||
if err != nil {
|
||
return "设置设备出口节点状态失败", err
|
||
}
|
||
} else {
|
||
err = h.DisableRoute(uint64(r.ID))
|
||
}
|
||
}
|
||
err = h.enableRoutes(machine, allowedIPs...)
|
||
if err != nil {
|
||
return "设置设备子网路由状态失败", err
|
||
}
|
||
return "", nil
|
||
}
|