Skip to content

Commit 3581328

Browse files
committed
add public key and registration
1 parent 3088ae1 commit 3581328

File tree

7 files changed

+318
-15
lines changed

7 files changed

+318
-15
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ COPY static/ static/
2929
RUN adduser -D appuser
3030
USER appuser
3131

32-
EXPOSE 8080
32+
EXPOSE 3000
3333

3434
CMD ["./main"]

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ reload:
1010
make apply
1111

1212
run:
13-
docker compose up
13+
docker compose up --force-recreate --build
1414

1515
pull-secrets:
1616
@echo "Creating static directory if it doesn't exist..."

docker-compose.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,5 @@ services:
2626
dockerfile: Dockerfile
2727
ports:
2828
- "3000:3000"
29-
# environment:
30-
# - TESLA_PROXY_URL=https://localhost:4443
3129
depends_on:
3230
- tesla-http-proxy

examples/kustomization/kustomization.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ resources:
66
- certificate.yaml
77
- tlsroute.yaml
88
- secrets.yaml
9-
9+
- public-key-webserver.yaml
1010
configMapGenerator:
1111
- name: fleet-telemetry-config
1212
files:
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: public-key-web-server
5+
labels:
6+
app: public-key-web-server
7+
spec:
8+
replicas: 1
9+
selector:
10+
matchLabels:
11+
app: public-key-web-server
12+
template:
13+
metadata:
14+
labels:
15+
app: public-key-web-server
16+
spec:
17+
containers:
18+
- name: web-server
19+
image: nginx:latest
20+
volumeMounts:
21+
- name: public-key-volume
22+
mountPath: /usr/share/nginx/html/public-key.pem
23+
subPath: public-key.pem
24+
- name: nginx-config
25+
mountPath: /etc/nginx/conf.d/default.conf
26+
subPath: default.conf
27+
ports:
28+
- containerPort: 80
29+
volumes:
30+
- name: public-key-volume
31+
secret:
32+
secretName: tesla-fleet-api
33+
items:
34+
- key: public-key.pem
35+
path: public-key.pem
36+
- name: nginx-config
37+
configMap:
38+
name: nginx-config
39+
---
40+
apiVersion: v1
41+
kind: ConfigMap
42+
metadata:
43+
name: nginx-config
44+
data:
45+
default.conf: |
46+
server {
47+
listen 80;
48+
location / {
49+
default_type application/x-pem-file;
50+
root /usr/share/nginx/html;
51+
try_files /public-key.pem =404;
52+
}
53+
}
54+
---
55+
apiVersion: v1
56+
kind: Service
57+
metadata:
58+
name: public-key-web-server
59+
spec:
60+
selector:
61+
app: public-key-web-server
62+
ports:
63+
- protocol: TCP
64+
port: 80
65+
targetPort: 80
66+
type: ClusterIP

main.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,127 @@
11
package main
22

33
import (
4+
"bytes"
5+
"encoding/json"
6+
"fmt"
7+
"io"
48
"log"
9+
"net/http"
10+
"net/url"
11+
"os"
12+
"strings"
513

614
"github.com/gofiber/fiber/v2"
715
"github.com/gofiber/template/html/v2"
816
)
917

18+
type TokenResponse struct {
19+
AccessToken string `json:"access_token"`
20+
TokenType string `json:"token_type"`
21+
ExpiresIn int `json:"expires_in"`
22+
}
23+
24+
type RegistrationResponse struct {
25+
ClientID string `json:"client_id"`
26+
Name string `json:"name"`
27+
Description string `json:"description"`
28+
Domain string `json:"domain"`
29+
CA interface{} `json:"ca"`
30+
CreatedAt string `json:"created_at"`
31+
UpdatedAt string `json:"updated_at"`
32+
EnterpriseTier string `json:"enterprise_tier"`
33+
PublicKey string `json:"public_key"`
34+
}
35+
36+
func generateToken() (*TokenResponse, error) {
37+
data := url.Values{}
38+
data.Set("grant_type", "client_credentials")
39+
data.Set("client_id", strings.TrimSpace(string(clientID)))
40+
data.Set("client_secret", strings.TrimSpace(string(clientSecret)))
41+
data.Set("scope", "openid vehicle_device_data vehicle_cmds vehicle_charging_cmds")
42+
data.Set("audience", "https://fleet-api.prd.na.vn.cloud.tesla.com")
43+
44+
resp, err := http.PostForm("https://auth.tesla.com/oauth2/v3/token", data)
45+
if err != nil {
46+
return nil, err
47+
}
48+
defer resp.Body.Close()
49+
50+
var tokenResp TokenResponse
51+
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
52+
return nil, err
53+
}
54+
55+
return &tokenResp, nil
56+
}
57+
58+
func registerPartnerAccount(token string) (*RegistrationResponse, error) {
59+
domain := strings.TrimSpace(string(domainName))
60+
payload := map[string]string{
61+
"domain": domain,
62+
}
63+
64+
jsonPayload, err := json.Marshal(payload)
65+
if err != nil {
66+
return nil, fmt.Errorf("error marshaling payload: %v", err)
67+
}
68+
69+
req, err := http.NewRequest("POST",
70+
"https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/partner_accounts",
71+
bytes.NewBuffer(jsonPayload))
72+
if err != nil {
73+
return nil, fmt.Errorf("error creating request: %v", err)
74+
}
75+
76+
req.Header.Set("Content-Type", "application/json")
77+
req.Header.Set("Authorization", "Bearer "+token)
78+
79+
client := &http.Client{}
80+
resp, err := client.Do(req)
81+
if err != nil {
82+
return nil, fmt.Errorf("error making request: %v", err)
83+
}
84+
defer resp.Body.Close()
85+
86+
body, err := io.ReadAll(resp.Body)
87+
if err != nil {
88+
return nil, fmt.Errorf("error reading response: %v", err)
89+
}
90+
91+
if resp.StatusCode != http.StatusOK {
92+
return nil, fmt.Errorf("registration failed with status %d: %s", resp.StatusCode, string(body))
93+
}
94+
95+
var regResp RegistrationResponse
96+
if err := json.Unmarshal(body, &regResp); err != nil {
97+
return nil, fmt.Errorf("error parsing response: %v", err)
98+
}
99+
100+
return &regResp, nil
101+
}
102+
103+
var (
104+
clientID []byte
105+
clientSecret []byte
106+
domainName []byte
107+
)
108+
10109
func main() {
110+
var err error
111+
// Read credentials
112+
clientID, err = os.ReadFile("static/CLIENT_ID")
113+
if err != nil {
114+
log.Fatal("Error reading CLIENT_ID:", err)
115+
}
116+
clientSecret, err = os.ReadFile("static/CLIENT_SECRET")
117+
if err != nil {
118+
log.Fatal("Error reading CLIENT_SECRET:", err)
119+
}
120+
domainName, err = os.ReadFile("static/DOMAIN")
121+
if err != nil {
122+
log.Fatal("Error reading DOMAIN:", err)
123+
}
124+
11125
// Create a new engine
12126
engine := html.New("./views", ".html")
13127

@@ -24,6 +138,30 @@ func main() {
24138
return c.SendFile("./static/public-key.pem")
25139
})
26140

141+
// Generate token and register partner account endpoint
142+
app.Post("/generate-token", func(c *fiber.Ctx) error {
143+
token, err := generateToken()
144+
if err != nil {
145+
return c.Status(500).JSON(fiber.Map{
146+
"error": "Token generation failed: " + err.Error(),
147+
})
148+
}
149+
150+
// Register partner account using the token
151+
regResp, err := registerPartnerAccount(token.AccessToken)
152+
if err != nil {
153+
return c.Status(500).JSON(fiber.Map{
154+
"error": "Registration failed: " + err.Error(),
155+
"token": token,
156+
})
157+
}
158+
159+
return c.JSON(fiber.Map{
160+
"token": token,
161+
"registration": regResp,
162+
})
163+
})
164+
27165
// Serve the main page
28166
app.Get("/", func(c *fiber.Ctx) error {
29167
return c.Render("index", fiber.Map{

0 commit comments

Comments
 (0)