{"record":{"id":"d4fe46b5737dc130","repo":"tonhowtf/omniget","slug":"para-desfazer-saves-informe-os-cookies-da-sua-sessao-com","errorCode":null,"errorMessage":"para desfazer saves informe os cookies da sua sessao (com csrftoken)","messagePattern":"para desfazer saves informe os cookies da sua sessao \\(com csrftoken\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/pinterest/api.rs","lineNumber":1243,"sourceCode":"                break;\n            }\n            let r = self.http.get(&loc).send().await?;\n            match r\n                .headers()\n                .get(reqwest::header::LOCATION)\n                .and_then(|v| v.to_str().ok())\n            {\n                Some(l) => loc = l.to_string(),\n                None => break,\n            }\n        }\n        Ok(loc.split(\"/sent/\").next().unwrap_or(&loc).to_string())\n    }\n\n    /// Desfaz o save de um pin seu (exige cookies com `csrftoken`).\n    pub async fn unsave(&self, pin_id: &str) -> anyhow::Result<()> {\n        let csrf = self.csrf.clone().ok_or_else(|| {\n            anyhow!(\"para desfazer saves informe os cookies da sua sessao (com csrftoken)\")\n        })?;\n        let data = json!({ \"options\": { \"id\": pin_id }, \"context\": {} }).to_string();\n        let req = self\n            .http\n            .post(format!(\"{}/resource/PinResource/delete/\", ROOT))\n            .header(\"X-CSRFToken\", csrf)\n            .header(\"Content-Type\", \"application/x-www-form-urlencoded\")\n            .form(&[(\"source_url\", format!(\"/pin/{}/\", pin_id)), (\"data\", data)]);\n        let resp = self.apply_cookie(req).send().await?;\n        let status = resp.status();\n        let body: Value = resp.json().await.unwrap_or(Value::Null);\n        if !status.is_success() || body[\"resource_response\"][\"status\"].as_str() != Some(\"success\") {\n            let msg = body[\"resource_response\"][\"error\"][\"message\"]\n                .as_str()\n                .unwrap_or(\"falhou\");\n            return Err(anyhow!(\n                \"nao consegui desfazer o save de {} (HTTP {}): {}\",\n                pin_id,","sourceCodeStart":1225,"sourceCodeEnd":1261,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/pinterest/api.rs#L1225-L1261","documentation":"unsave() performs an authenticated POST to PinResource/delete, which requires the csrftoken from the user's Pinterest session cookies. The client's stored `csrf` Option is None, so the call fails fast with this message before making any network request. It is a precondition error: write operations simply cannot proceed without session credentials.","triggerScenarios":"Calling PinterestApi::unsave(pin_id) on a client built without cookies, or with cookies that lack the csrftoken entry.","commonSituations":"Users configured the app for read-only scraping (anonymous client) and then try a write action; cookies pasted from a browser export missing csrftoken; cookies cleared on app restart.","solutions":["Re-create the client with full session cookies copied from a logged-in browser session (must include csrftoken).","Check the cookie string actually contains `csrftoken=...` before constructing the client.","Re-export cookies if the Pinterest session expired and csrftoken was rotated.","Gate the unsave feature in UI code behind a check that cookies are configured."],"exampleFix":"// before\nlet api = PinterestApi::new(None); // no cookies\napi.unsave(&pin_id).await?;\n// after\nlet cookies = env::var(\"PINTEREST_COOKIES\")?;\nanyhow::ensure!(cookies.contains(\"csrftoken=\"), \"cookies must include csrftoken\");\nlet api = PinterestApi::new(Some(cookies));\napi.unsave(&pin_id).await?;","handlingStrategy":"validation","validationCode":"fn cookies_have_csrf(cookies: &str) -> bool {\n    cookies.split(';').any(|c| c.trim().starts_with(\"csrftoken=\"))\n}","typeGuard":"null","tryCatchPattern":"match api.unsave(&pin_id).await {\n    Err(e) if e.to_string().contains(\"csrftoken\") => {\n        prompt_user(\"Paste cookies including csrftoken\");\n    }\n    other => other?,\n}","preventionTips":["Check for csrftoken= in the cookie string before building the client","Re-export cookies after Pinterest rotates the token","Gate write features in UI behind a cookies-configured check","Never build the client from a partial cookie export"],"tags":["pinterest","csrf","authentication","cookies"],"backgroundTag":"authentication-required","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}