{"record":{"id":"090a84ea39ef6f75","repo":"AlexxIT/go2rtc","slug":"no-auth","errorCode":null,"errorMessage":"no auth","messagePattern":"no auth","errorType":"http","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"internal/roborock/roborock.go","lineNumber":30,"sourceCode":"\nfunc Init() {\n\tstreams.HandleFunc(\"roborock\", func(source string) (core.Producer, error) {\n\t\treturn roborock.Dial(source)\n\t})\n\n\tapi.HandleFunc(\"api/roborock\", apiHandle)\n}\n\nvar Auth struct {\n\tUserData *roborock.UserInfo `json:\"user_data\"`\n\tBaseURL  string             `json:\"base_url\"`\n}\n\nfunc apiHandle(w http.ResponseWriter, r *http.Request) {\n\tswitch r.Method {\n\tcase \"GET\":\n\t\tif Auth.UserData == nil {\n\t\t\thttp.Error(w, \"no auth\", http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\n\tcase \"POST\":\n\t\tif err := r.ParseMultipartForm(1024); err != nil {\n\t\t\thttp.Error(w, err.Error(), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\n\t\tusername := r.Form.Get(\"username\")\n\t\tpassword := r.Form.Get(\"password\")\n\t\tif username == \"\" || password == \"\" {\n\t\t\thttp.Error(w, \"empty username or password\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\n\t\tbase, err := roborock.GetBaseURL(username)\n\t\tif err != nil {","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/AlexxIT/go2rtc/blob/c245815e75e2a5fd60b4290f12bfc04e55a984d3/internal/roborock/roborock.go#L12-L48","documentation":"A GET request reached the roborock API handler before any login was performed. Auth.UserData is nil because no prior POST populated the session, so the handler rejects the request with 'no auth' and HTTP 404.","triggerScenarios":"GET to the roborock API endpoint with no preceding successful POST /login in the same process; server restarted (Auth is in-memory) so UserData was reset to nil.","commonSituations":"Client hits GET before authenticating; server process restarted clearing in-memory session state; session cookie/token not sent by the client.","solutions":["POST username/password first to authenticate, then issue the GET request","Persist or re-establish the session after server restarts","Return 401 instead of 404 and include a hint to authenticate first"],"exampleFix":"// before\ncase \"GET\":\n\tif Auth.UserData == nil {\n\t\thttp.Error(w, \"no auth\", http.StatusNotFound)\n\t\treturn\n\t}\n// after\ncase \"GET\":\n\tif Auth.UserData == nil {\n\t\thttp.Error(w, \"not authenticated: POST username and password first\", http.StatusUnauthorized)\n\t\treturn\n\t}","handlingStrategy":"validation","validationCode":"if Auth.UserData == nil {\n\t// redirect to login or return 401 before issuing GET requests\n}","typeGuard":"func isAuthenticated(a *AuthState) bool { return a != nil && a.UserData != nil && a.UserData.Token != \"\" }","tryCatchPattern":null,"preventionTips":["Always POST credentials before issuing GET device requests","Persist session state or re-login after server restarts","Have clients check an auth status endpoint before calling GET","Use 401 with a clear message so clients know to authenticate"],"tags":["go","http","authentication","session"],"backgroundTag":"authentication-required","analyzedSha":"c245815e75e2a5fd60b4290f12bfc04e55a984d3","analyzedAt":"2026-09-07T11:47:02.965Z","contentChangedAt":"2026-09-07T11:47:02.965Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}