masto.go (view raw)
1package main
2
3import (
4 "database/sql"
5 "fmt"
6 "log"
7 "net/http"
8
9 "humungus.tedunangst.com/r/webs/junk"
10 "humungus.tedunangst.com/r/webs/login"
11)
12
13type MastoApp struct {
14 Name string `db:"clientname"`
15 RedirectURI string `db:"redirecturi"`
16 ClientID string `db:"clientid"`
17 ClientSecret string `db:"clientsecret"`
18 VapidKey string `db:"vapidkey"`
19 AuthToken string `db:"authtoken"`
20 Scopes string `db:"scopes"`
21}
22
23func showoauthlogin(rw http.ResponseWriter, r *http.Request) {
24 templinfo := make(map[string]interface{})
25 templinfo = getInfo(r)
26 templinfo["ClientID"] = r.URL.Query().Get("client_id")
27 templinfo["RedirectURI"] = r.URL.Query().Get("redirect_uri")
28
29 if err := readviews.Execute(rw, "oauthlogin.html", templinfo); err != nil {
30 elog.Println(err)
31 }
32}
33
34// https://docs.joinmastodon.org/methods/apps/#create
35func apiapps(rw http.ResponseWriter, r *http.Request) {
36 if err := r.ParseForm(); err != nil {
37 http.Error(rw, "invalid input", http.StatusUnprocessableEntity)
38 elog.Println(err)
39 return
40 }
41 clientName := r.Form.Get("client_name")
42 redirectURI := r.Form.Get("redirect_uris")
43 scopes := r.Form.Get("scopes")
44 website := r.Form.Get("website")
45 clientID := tokengen()
46 clientSecret := tokengen()
47 vapidKey := tokengen()
48
49 _, err := stmtSaveMastoApp.Exec(clientName, redirectURI, scopes, clientID, clientSecret, vapidKey, "")
50 if err != nil {
51 elog.Printf("error saving masto app: %v", err)
52 http.Error(rw, "error saving masto app", http.StatusUnprocessableEntity)
53 return
54 }
55
56 j := junk.New()
57 j["id"] = "19"
58 j["website"] = website
59 j["name"] = clientName
60 j["redirect_uri"] = redirectURI
61 j["client_id"] = clientID
62 j["client_secret"] = clientSecret
63 j["vapid_key"] = vapidKey
64
65 fmt.Println(j.ToString())
66 goodjunk(rw, j)
67}
68
69// https://docs.joinmastodon.org/methods/oauth/#authorize
70func oauthorize(rw http.ResponseWriter, r *http.Request) {
71 clientID := r.FormValue("client_id")
72 redirectURI := r.FormValue("redirect_uri")
73
74 err := stmtCheckClientId.QueryRow(clientID).Scan()
75 if err == sql.ErrNoRows {
76 elog.Println("oauth: no such client:", clientID)
77 rw.WriteHeader(http.StatusUnauthorized)
78 return
79 }
80
81 var nrw NotResponseWriter
82 login.LoginFunc(&nrw, r)
83
84 _, err = stmtSaveMastoAppToken.Exec(nrw.auth)
85 if err != nil {
86 elog.Println("oauth: failed to save masto app token", err)
87 rw.WriteHeader(http.StatusInternalServerError)
88 return
89 }
90
91 uri := fmt.Sprintf("%s?code=%s", redirectURI, nrw.auth)
92
93 log.Println("redirecting to", uri)
94 rw.Header().Set("Content-Type", "")
95 rw.Header().Set("Location", uri)
96 rw.WriteHeader(302)
97}
98
99// https://docs.joinmastodon.org/methods/oauth/#token
100func oauthtoken(rw http.ResponseWriter, r *http.Request) {
101 // grantType := r.FormValue("grant_type")
102 // code := r.FormValue("code")
103 clientID := r.FormValue("client_id")
104 // clientSecret := r.FormValue("client_Secret")
105 // redirectURI := r.FormValue("redirect_uri")
106 // gotScopes := r.FormValue("scopes")
107
108 app := MastoApp{}
109 err := stmtGetMastoApp.Select(&app, clientID)
110 if err == sql.ErrNoRows {
111 elog.Println("oauth: no such client:", clientID)
112 rw.WriteHeader(http.StatusUnauthorized)
113 return
114 }
115
116}
117
118// https://docs.joinmastodon.org/methods/instance/#v2
119func instance(rw http.ResponseWriter, r *http.Request) {
120 j := junk.New()
121
122 var servername string
123 if err := getconfig("servername", &servername); err != nil {
124 http.Error(rw, "getting servername", http.StatusInternalServerError)
125 return
126 }
127
128 j["uri"] = servername
129 j["title"] = "honk"
130 j["description"] = "federated honk conveyance"
131 j["version"] = "develop"
132
133 thumbnail := junk.New()
134 thumbnail["url"] = fmt.Sprintf("https://%s/icon.png", servername)
135 j["thumbnail"] = thumbnail
136 j["languages"] = []string{"en"}
137
138 config := junk.New()
139
140 a := junk.New()
141 a["max_featured_tags"] = 10
142 config["accounts"] = a
143
144 s := junk.New()
145 s["max_characters"] = 5000
146 s["max_media_attachments"] = 1
147 s["characters_reserved_per_url"] = 23
148 config["statuses"] = s
149
150 m := junk.New()
151 m["supported_mime_types"] = []string{
152 "image/jpeg",
153 "image/png",
154 "image/gif",
155 "image/heic",
156 "image/heif",
157 "image/webp",
158 "image/avif",
159 "video/webm",
160 "video/mp4",
161 "video/quicktime",
162 "video/ogg",
163 "audio/wave",
164 "audio/wav",
165 "audio/x-wav",
166 "audio/x-pn-wave",
167 "audio/vnd.wave",
168 "audio/ogg",
169 "audio/vorbis",
170 "audio/mpeg",
171 "audio/mp3",
172 "audio/webm",
173 "audio/flac",
174 "audio/aac",
175 "audio/m4a",
176 "audio/x-m4a",
177 "audio/mp4",
178 "audio/3gpp",
179 "video/x-ms-asf",
180 }
181
182 m["image_size_limit"] = 10485760
183 m["image_matrix_limit"] = 16777216
184 m["video_size_limit"] = 41943040
185 m["video_frame_rate_limit"] = 60
186 m["video_matrix_limit"] = 2304000
187 j["media_attachments"] = m
188
189 goodjunk(rw, j)
190
191 return
192}