Skip to content

Commit 1d0a896

Browse files
authored
Parse user agent into a human-friendly string on submission (#86)
I've had to look up UA's far too many times
1 parent 7a7a0fb commit 1d0a896

File tree

5 files changed

+44
-2
lines changed

5 files changed

+44
-2
lines changed

changelog.d/86.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Parse User-Agent into a human readable format and attach to the report alongside the raw UA string.

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.16
55
require (
66
github.com/google/go-github v0.0.0-20170401000335-12363ffc1001
77
github.com/jordan-wright/email v4.0.1-0.20200824153738-3f5bafa1cd84+incompatible
8+
github.com/ua-parser/uap-go v0.0.0-20241012191800-bbb40edc15aa // indirect
89
github.com/xanzy/go-gitlab v0.50.2
910
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288
1011
gopkg.in/yaml.v2 v2.2.8

go.sum

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxC
1313
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
1414
github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs=
1515
github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
16+
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
17+
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
1618
github.com/jordan-wright/email v4.0.1-0.20200824153738-3f5bafa1cd84+incompatible h1:d60x4RsAHk/UX/0OT8Gc6D7scVvhBbEANpTAWrDhA/I=
1719
github.com/jordan-wright/email v4.0.1-0.20200824153738-3f5bafa1cd84+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
1820
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -21,6 +23,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
2123
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
2224
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
2325
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
26+
github.com/ua-parser/uap-go v0.0.0-20241012191800-bbb40edc15aa h1:VzPR4xFM7HARqNocjdHg75ZL9SAgFtaF3P57ZdDcG6I=
27+
github.com/ua-parser/uap-go v0.0.0-20241012191800-bbb40edc15aa/go.mod h1:BUbeWZiieNxAuuADTBNb3/aeje6on3DhU3rpWsQSB1E=
2428
github.com/xanzy/go-gitlab v0.50.2 h1:Qm/um2Jryuqusc6VmN7iZYVTQVzNynzSiuMJDnCU1wE=
2529
github.com/xanzy/go-gitlab v0.50.2/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE=
2630
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -45,6 +49,7 @@ google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQ
4549
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
4650
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
4751
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
52+
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
4853
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
4954
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
5055
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

submit.go

+10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"encoding/base32"
2424
"encoding/json"
2525
"fmt"
26+
"github.com/ua-parser/uap-go/uaparser"
2627
"io"
2728
"io/ioutil"
2829
"log"
@@ -291,6 +292,13 @@ func parseRequest(w http.ResponseWriter, req *http.Request, reportDir string) *p
291292
return p
292293
}
293294

295+
var uaParser *uaparser.Parser = uaparser.NewFromSaved()
296+
297+
func parseUserAgent(userAgent string) string {
298+
client := uaParser.Parse(userAgent)
299+
return fmt.Sprintf(`%s on %s running on %s device`, client.UserAgent.ToString(), client.Os.ToString(), client.Device.ToString())
300+
}
301+
294302
func parseJSONRequest(w http.ResponseWriter, req *http.Request, reportDir string) (*payload, error) {
295303
var p jsonPayload
296304
if err := json.NewDecoder(req.Body).Decode(&p); err != nil {
@@ -321,6 +329,7 @@ func parseJSONRequest(w http.ResponseWriter, req *http.Request, reportDir string
321329
parsed.AppName = p.AppName
322330

323331
if p.UserAgent != "" {
332+
parsed.Data["Parsed-User-Agent"] = parseUserAgent(p.UserAgent)
324333
parsed.Data["User-Agent"] = p.UserAgent
325334
}
326335
if p.Version != "" {
@@ -425,6 +434,7 @@ func formPartToPayload(field, data string, p *payload) {
425434
p.Data["Version"] = data
426435
} else if field == "user_agent" {
427436
p.Data["User-Agent"] = data
437+
p.Data["Parsed-User-Agent"] = parseUserAgent(data)
428438
} else if field == "label" {
429439
p.Labels = append(p.Labels, data)
430440
} else {

submit_test.go

+27-2
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,9 @@ func checkParsedMultipartUpload(t *testing.T, p *payload) {
259259
if len(p.Logs) != 4 {
260260
t.Errorf("Log length: got %d, want 4", len(p.Logs))
261261
}
262-
if len(p.Data) != 3 {
263-
t.Errorf("Data length: got %d, want 3", len(p.Data))
262+
// One extra data field to account for User Agent being parsed into two fields
263+
if len(p.Data) != 4 {
264+
t.Errorf("Data length: got %d, want 4", len(p.Data))
264265
}
265266
if len(p.Labels) != 0 {
266267
t.Errorf("Labels: got %#v, want []", p.Labels)
@@ -588,3 +589,27 @@ user_id: id
588589
}
589590
}
590591
}
592+
593+
func TestParseUserAgent(t *testing.T) {
594+
reportDir := mkTempDir(t)
595+
defer os.RemoveAll(reportDir)
596+
597+
body := `{
598+
"app": "riot-web",
599+
"logs": [],
600+
"text": "test message",
601+
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.91 Safari/537.3",
602+
"version": "0.9.9"
603+
}`
604+
605+
p, _ := testParsePayload(t, body, "application/json", reportDir)
606+
607+
if p == nil {
608+
t.Fatal("parseRequest returned nil")
609+
}
610+
611+
wanted := "Chrome 130.0.6723 on Windows 10 running on Other device"
612+
if p.Data["Parsed-User-Agent"] != wanted {
613+
t.Errorf("user agent: got %s, want %s", p.Data["Parsed-User-Agent"], wanted)
614+
}
615+
}

0 commit comments

Comments
 (0)