Skip to content

Commit 3a174f8

Browse files
committed
local-copy
1 parent a9f6554 commit 3a174f8

5 files changed

Lines changed: 321 additions & 1 deletion

File tree

blockchain/bl_autopin.go

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package blockchain
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/json"
7+
"fmt"
8+
"io"
9+
"net/http"
10+
11+
"github.com/functionland/go-fula/wap/pkg/config"
12+
wifi "github.com/functionland/go-fula/wap/pkg/wifi"
13+
"github.com/google/uuid"
14+
"github.com/libp2p/go-libp2p/core/network"
15+
"github.com/libp2p/go-libp2p/core/peer"
16+
)
17+
18+
// handleAutoPinPair handles the auto-pin-pair action on the device side.
19+
// It stores pinning credentials in box_props.json and returns a pairing secret.
20+
func (bl *FxBlockchain) handleAutoPinPair(from peer.ID, w http.ResponseWriter, r *http.Request) {
21+
log := log.With("action", actionAutoPinPair, "from", from)
22+
defer r.Body.Close()
23+
24+
var req AutoPinPairRequest
25+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
26+
log.Debugw("cannot parse request body", "err", err)
27+
http.Error(w, "", http.StatusBadRequest)
28+
return
29+
}
30+
31+
if req.PinningToken == "" || req.PinningEndpoint == "" {
32+
http.Error(w, `{"message":"pinning_token and pinning_endpoint are required"}`, http.StatusBadRequest)
33+
return
34+
}
35+
36+
// Read current properties
37+
props, err := config.ReadProperties()
38+
if err != nil {
39+
// File may not exist yet; start fresh
40+
props = make(map[string]interface{})
41+
}
42+
43+
// Reject if already paired
44+
if existingToken, ok := props["auto_pin_token"]; ok && existingToken != nil && existingToken != "" {
45+
http.Error(w, `{"message":"already paired, unpair first"}`, http.StatusConflict)
46+
return
47+
}
48+
49+
// Generate pairing secret
50+
pairingSecret := uuid.New().String()
51+
52+
// Store credentials
53+
props["auto_pin_token"] = req.PinningToken
54+
props["auto_pin_endpoint"] = req.PinningEndpoint
55+
props["auto_pin_pairing_secret"] = pairingSecret
56+
57+
if err := config.WriteProperties(props); err != nil {
58+
log.Errorw("failed to write properties", "err", err)
59+
http.Error(w, `{"message":"failed to save pairing config"}`, http.StatusInternalServerError)
60+
return
61+
}
62+
63+
// Get hardware ID for response
64+
hardwareID, err := wifi.GetHardwareID()
65+
if err != nil {
66+
log.Warnw("failed to get hardware ID", "err", err)
67+
hardwareID = ""
68+
}
69+
70+
resp := AutoPinPairResponse{
71+
Status: "paired",
72+
PairingSecret: pairingSecret,
73+
HardwareID: hardwareID,
74+
}
75+
76+
w.Header().Set("Content-Type", "application/json")
77+
w.WriteHeader(http.StatusOK)
78+
json.NewEncoder(w).Encode(resp)
79+
}
80+
81+
// handleAutoPinRefresh handles refreshing the pinning service token.
82+
func (bl *FxBlockchain) handleAutoPinRefresh(from peer.ID, w http.ResponseWriter, r *http.Request) {
83+
log := log.With("action", actionAutoPinRefresh, "from", from)
84+
defer r.Body.Close()
85+
86+
var req AutoPinRefreshRequest
87+
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
88+
log.Debugw("cannot parse request body", "err", err)
89+
http.Error(w, "", http.StatusBadRequest)
90+
return
91+
}
92+
93+
if req.PinningToken == "" {
94+
http.Error(w, `{"message":"pinning_token is required"}`, http.StatusBadRequest)
95+
return
96+
}
97+
98+
props, err := config.ReadProperties()
99+
if err != nil {
100+
http.Error(w, `{"message":"not paired"}`, http.StatusNotFound)
101+
return
102+
}
103+
104+
if _, ok := props["auto_pin_token"]; !ok {
105+
http.Error(w, `{"message":"not paired"}`, http.StatusNotFound)
106+
return
107+
}
108+
109+
props["auto_pin_token"] = req.PinningToken
110+
if err := config.WriteProperties(props); err != nil {
111+
log.Errorw("failed to write properties", "err", err)
112+
http.Error(w, `{"message":"failed to update token"}`, http.StatusInternalServerError)
113+
return
114+
}
115+
116+
w.Header().Set("Content-Type", "application/json")
117+
w.WriteHeader(http.StatusOK)
118+
json.NewEncoder(w).Encode(AutoPinRefreshResponse{Status: "refreshed"})
119+
}
120+
121+
// handleAutoPinUnpair removes auto-pin configuration.
122+
func (bl *FxBlockchain) handleAutoPinUnpair(from peer.ID, w http.ResponseWriter, r *http.Request) {
123+
log := log.With("action", actionAutoPinUnpair, "from", from)
124+
defer r.Body.Close()
125+
126+
props, err := config.ReadProperties()
127+
if err != nil {
128+
http.Error(w, `{"message":"not paired"}`, http.StatusNotFound)
129+
return
130+
}
131+
132+
delete(props, "auto_pin_token")
133+
delete(props, "auto_pin_endpoint")
134+
delete(props, "auto_pin_pairing_secret")
135+
136+
if err := config.WriteProperties(props); err != nil {
137+
log.Errorw("failed to write properties", "err", err)
138+
http.Error(w, `{"message":"failed to remove pairing config"}`, http.StatusInternalServerError)
139+
return
140+
}
141+
142+
w.Header().Set("Content-Type", "application/json")
143+
w.WriteHeader(http.StatusOK)
144+
json.NewEncoder(w).Encode(AutoPinUnpairResponse{Status: "unpaired"})
145+
}
146+
147+
// AutoPinPair is the P2P client-side method for the mobile bridge.
148+
func (bl *FxBlockchain) AutoPinPair(ctx context.Context, to peer.ID, r AutoPinPairRequest) ([]byte, error) {
149+
if bl.allowTransientConnection {
150+
ctx = network.WithUseTransient(ctx, "fx.blockchain")
151+
}
152+
153+
var buf bytes.Buffer
154+
if err := json.NewEncoder(&buf).Encode(r); err != nil {
155+
return nil, err
156+
}
157+
158+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://"+to.String()+".invalid/"+actionAutoPinPair, &buf)
159+
if err != nil {
160+
return nil, err
161+
}
162+
resp, err := bl.doP2PRequest(req)
163+
if err != nil {
164+
return nil, err
165+
}
166+
defer resp.Body.Close()
167+
b, err := io.ReadAll(resp.Body)
168+
169+
switch {
170+
case err != nil:
171+
return nil, err
172+
case resp.StatusCode != http.StatusOK:
173+
return nil, fmt.Errorf("unexpected response: %d %s", resp.StatusCode, string(b))
174+
default:
175+
return b, nil
176+
}
177+
}
178+
179+
// AutoPinRefresh is the P2P client-side method for the mobile bridge.
180+
func (bl *FxBlockchain) AutoPinRefresh(ctx context.Context, to peer.ID, r AutoPinRefreshRequest) ([]byte, error) {
181+
if bl.allowTransientConnection {
182+
ctx = network.WithUseTransient(ctx, "fx.blockchain")
183+
}
184+
185+
var buf bytes.Buffer
186+
if err := json.NewEncoder(&buf).Encode(r); err != nil {
187+
return nil, err
188+
}
189+
190+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://"+to.String()+".invalid/"+actionAutoPinRefresh, &buf)
191+
if err != nil {
192+
return nil, err
193+
}
194+
resp, err := bl.doP2PRequest(req)
195+
if err != nil {
196+
return nil, err
197+
}
198+
defer resp.Body.Close()
199+
b, err := io.ReadAll(resp.Body)
200+
201+
switch {
202+
case err != nil:
203+
return nil, err
204+
case resp.StatusCode != http.StatusOK:
205+
return nil, fmt.Errorf("unexpected response: %d %s", resp.StatusCode, string(b))
206+
default:
207+
return b, nil
208+
}
209+
}
210+
211+
// AutoPinUnpair is the P2P client-side method for the mobile bridge.
212+
func (bl *FxBlockchain) AutoPinUnpair(ctx context.Context, to peer.ID) ([]byte, error) {
213+
if bl.allowTransientConnection {
214+
ctx = network.WithUseTransient(ctx, "fx.blockchain")
215+
}
216+
217+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://"+to.String()+".invalid/"+actionAutoPinUnpair, nil)
218+
if err != nil {
219+
return nil, err
220+
}
221+
resp, err := bl.doP2PRequest(req)
222+
if err != nil {
223+
return nil, err
224+
}
225+
defer resp.Body.Close()
226+
b, err := io.ReadAll(resp.Body)
227+
228+
switch {
229+
case err != nil:
230+
return nil, err
231+
case resp.StatusCode != http.StatusOK:
232+
return nil, fmt.Errorf("unexpected response: %d %s", resp.StatusCode, string(b))
233+
default:
234+
return b, nil
235+
}
236+
}

blockchain/blockchain.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,17 @@ func (bl *FxBlockchain) dispatch(from peer.ID, action string, w http.ResponseWri
613613
actionUpdatePlugin: func(from peer.ID, w http.ResponseWriter, r *http.Request) {
614614
bl.handlePluginAction(r.Context(), from, w, r, actionUpdatePlugin)
615615
},
616+
617+
// Auto-pin actions
618+
actionAutoPinPair: func(from peer.ID, w http.ResponseWriter, r *http.Request) {
619+
bl.handleAutoPinPair(from, w, r)
620+
},
621+
actionAutoPinRefresh: func(from peer.ID, w http.ResponseWriter, r *http.Request) {
622+
bl.handleAutoPinRefresh(from, w, r)
623+
},
624+
actionAutoPinUnpair: func(from peer.ID, w http.ResponseWriter, r *http.Request) {
625+
bl.handleAutoPinUnpair(from, w, r)
626+
},
616627
}
617628

618629
// Look up the function in the map and call it
@@ -1002,7 +1013,7 @@ func (bl *FxBlockchain) authorized(pid peer.ID, action string) bool {
10021013
switch action {
10031014
case actionReplicateInPool:
10041015
return (bl.authorizer == bl.selfPeerID || bl.authorizer == "")
1005-
case actionBloxFreeSpace, actionAccountFund, actionManifestBatchUpload, actionAssetsBalance, actionGetDatastoreSize, actionGetFolderSize, actionFindBestAndTargetInLogs, actionFetchContainerLogs, actionChatWithAI, actionEraseBlData, actionWifiRemoveall, actionReboot, actionPartition, actionDeleteWifi, actionDisconnectWifi, actionDeleteFulaConfig, actionGetAccount, actionSeeded, actionAccountExists, actionPoolCreate, actionPoolJoin, actionPoolCancelJoin, actionPoolRequests, actionPoolList, actionPoolVote, actionPoolLeave, actionManifestUpload, actionManifestStore, actionManifestAvailable, actionManifestRemove, actionManifestRemoveStorer, actionManifestRemoveStored, actionTransferToMumbai, actionListPlugins, actionListActivePlugins, actionInstallPlugin, actionUninstallPlugin, actionGetInstallStatus, actionGetInstallOutput, actionUpdatePlugin, actionGetDockerImageBuildDates, actionGetClusterInfo:
1016+
case actionBloxFreeSpace, actionAccountFund, actionManifestBatchUpload, actionAssetsBalance, actionGetDatastoreSize, actionGetFolderSize, actionFindBestAndTargetInLogs, actionFetchContainerLogs, actionChatWithAI, actionEraseBlData, actionWifiRemoveall, actionReboot, actionPartition, actionDeleteWifi, actionDisconnectWifi, actionDeleteFulaConfig, actionGetAccount, actionSeeded, actionAccountExists, actionPoolCreate, actionPoolJoin, actionPoolCancelJoin, actionPoolRequests, actionPoolList, actionPoolVote, actionPoolLeave, actionManifestUpload, actionManifestStore, actionManifestAvailable, actionManifestRemove, actionManifestRemoveStorer, actionManifestRemoveStored, actionTransferToMumbai, actionListPlugins, actionListActivePlugins, actionInstallPlugin, actionUninstallPlugin, actionGetInstallStatus, actionGetInstallOutput, actionUpdatePlugin, actionGetDockerImageBuildDates, actionGetClusterInfo, actionAutoPinPair, actionAutoPinRefresh, actionAutoPinUnpair:
10061017
bl.authorizedPeersLock.RLock()
10071018
_, ok := bl.authorizedPeers[pid]
10081019
bl.authorizedPeersLock.RUnlock()

blockchain/interface.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ const (
6969

7070
// AI
7171
actionChatWithAI = "chat-ai"
72+
73+
// Auto-pin (personal device pinning)
74+
actionAutoPinPair = "auto-pin-pair"
75+
actionAutoPinRefresh = "auto-pin-refresh"
76+
actionAutoPinUnpair = "auto-pin-unpair"
7277
)
7378

7479
type ReplicateRequest struct {
@@ -513,6 +518,29 @@ type UpdatePluginResponse struct {
513518
Status bool `json:"status"`
514519
}
515520

521+
// Auto-pin (personal device pinning)
522+
type AutoPinPairRequest struct {
523+
PinningToken string `json:"pinning_token"`
524+
PinningEndpoint string `json:"pinning_endpoint"`
525+
}
526+
type AutoPinPairResponse struct {
527+
Status string `json:"status"`
528+
PairingSecret string `json:"pairing_secret"`
529+
HardwareID string `json:"hardware_id"`
530+
}
531+
532+
type AutoPinRefreshRequest struct {
533+
PinningToken string `json:"pinning_token"`
534+
}
535+
type AutoPinRefreshResponse struct {
536+
Status string `json:"status"`
537+
}
538+
539+
type AutoPinUnpairRequest struct{}
540+
type AutoPinUnpairResponse struct {
541+
Status string `json:"status"`
542+
}
543+
516544
type Blockchain interface {
517545
Seeded(context.Context, peer.ID, SeededRequest) ([]byte, error)
518546
AccountExists(context.Context, peer.ID, AccountExistsRequest) ([]byte, error)
@@ -569,6 +597,11 @@ type Blockchain interface {
569597

570598
// AI
571599
ChatWithAI(context.Context, peer.ID, wifi.ChatWithAIRequest) (*StreamBuffer, error)
600+
601+
// Auto-pin
602+
AutoPinPair(context.Context, peer.ID, AutoPinPairRequest) ([]byte, error)
603+
AutoPinRefresh(context.Context, peer.ID, AutoPinRefreshRequest) ([]byte, error)
604+
AutoPinUnpair(context.Context, peer.ID) ([]byte, error)
572605
}
573606

574607
var requestTypes = map[string]reflect.Type{
@@ -628,6 +661,11 @@ var requestTypes = map[string]reflect.Type{
628661

629662
// AI
630663
actionChatWithAI: reflect.TypeOf(wifi.ChatWithAIRequest{}),
664+
665+
// Auto-pin
666+
actionAutoPinPair: reflect.TypeOf(AutoPinPairRequest{}),
667+
actionAutoPinRefresh: reflect.TypeOf(AutoPinRefreshRequest{}),
668+
actionAutoPinUnpair: reflect.TypeOf(AutoPinUnpairRequest{}),
631669
}
632670

633671
var responseTypes = map[string]reflect.Type{
@@ -687,4 +725,9 @@ var responseTypes = map[string]reflect.Type{
687725

688726
// AI
689727
actionChatWithAI: reflect.TypeOf(wifi.ChatWithAIResponse{}),
728+
729+
// Auto-pin
730+
actionAutoPinPair: reflect.TypeOf(AutoPinPairResponse{}),
731+
actionAutoPinRefresh: reflect.TypeOf(AutoPinRefreshResponse{}),
732+
actionAutoPinUnpair: reflect.TypeOf(AutoPinUnpairResponse{}),
690733
}

mobile/blockchain.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,3 +412,30 @@ func (c *Client) UpdatePlugin(pluginName string) ([]byte, error) {
412412
ctx := context.TODO()
413413
return c.bl.UpdatePlugin(ctx, c.bloxPid, pluginName)
414414
}
415+
416+
//////////////////////////////////////////////////
417+
////////////////////AUTO-PIN//////////////////////
418+
//////////////////////////////////////////////////
419+
420+
// AutoPinPair sends a pairing request to the blox with pinning service credentials.
421+
func (c *Client) AutoPinPair(token string, endpoint string) ([]byte, error) {
422+
ctx := context.TODO()
423+
return c.bl.AutoPinPair(ctx, c.bloxPid, blockchain.AutoPinPairRequest{
424+
PinningToken: token,
425+
PinningEndpoint: endpoint,
426+
})
427+
}
428+
429+
// AutoPinRefresh refreshes the pinning service token on the blox.
430+
func (c *Client) AutoPinRefresh(token string) ([]byte, error) {
431+
ctx := context.TODO()
432+
return c.bl.AutoPinRefresh(ctx, c.bloxPid, blockchain.AutoPinRefreshRequest{
433+
PinningToken: token,
434+
})
435+
}
436+
437+
// AutoPinUnpair removes auto-pin configuration from the blox.
438+
func (c *Client) AutoPinUnpair() ([]byte, error) {
439+
ctx := context.TODO()
440+
return c.bl.AutoPinUnpair(ctx, c.bloxPid)
441+
}

wap/cmd/mdns/mdns.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ func createInfo() []string {
160160
"poolName=" + globalConfig.PoolName,
161161
"authorizer=" + globalConfig.Authorizer,
162162
"hardwareID=" + globalConfig.HardwareID,
163+
"gatewayPort=8080",
164+
"autoPinPort=3501",
165+
"s3Port=9000",
163166
}
164167

165168
return infoSlice

0 commit comments

Comments
 (0)