{"action":"closed","issue":{"url":"https://api.github.com/repos/snarfed/bridgy/issues/414","labels_url":"https://api.github.com/repos/snarfed/bridgy/issues/414/labels{/name}","comments_url":"https://api.github.com/repos/snarfed/bridgy/issues/414/comments","events_url":"https://api.github.com/repos/snarfed/bridgy/issues/414/events","html_url":"https://github.com/snarfed/bridgy/issues/414","id":83601915,"number":414,"title":"odd broken twitter publish attempt","user":{"login":"snarfed","id":778068,"avatar_url":"https://avatars.githubusercontent.com/u/778068?v=3","gravatar_id":"","url":"https://api.github.com/users/snarfed","html_url":"https://github.com/snarfed","followers_url":"https://api.github.com/users/snarfed/followers","following_url":"https://api.github.com/users/snarfed/following{/other_user}","gists_url":"https://api.github.com/users/snarfed/gists{/gist_id}","starred_url":"https://api.github.com/users/snarfed/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/snarfed/subscriptions","organizations_url":"https://api.github.com/users/snarfed/orgs","repos_url":"https://api.github.com/users/snarfed/repos","events_url":"https://api.github.com/users/snarfed/events{/privacy}","received_events_url":"https://api.github.com/users/snarfed/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/snarfed/bridgy/labels/publish","name":"publish","color":"5319e7"}],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":5,"created_at":"2015-06-01T16:55:05Z","updated_at":"2015-06-11T14:36:46Z","closed_at":"2015-06-11T14:36:46Z","body":"this is weird. yesterday morning around 2:30AM PST we had a strange failed twitter publish attempt.\r\n\r\n1. we got a GET to `/twitter/publish/start` that successfully generated an OAuth request and redirected to twitter for approval\r\n1.  they approved and got redirected back to `/publish/twitter/finish`\r\n1. that request had no state param, so it failed there.\r\n\r\nrequest logs below, [and here](https://console.developers.google.com/project/brid-gy/logs?service=appengine.googleapis.com&key1=default&key2=3&logName=appengine.googleapis.com%2Frequest_log&minLogLevel=0&expandAll=false&timezone=America%2FLos_Angeles&filters=text:AhyH0Fvm).\r\n\r\nmysteries:\r\n* it should have been a POST to `/twitter/publish/start` not a GET. the only place in the codebase that points there is the form in [templates/preview.html](https://github.com/snarfed/bridgy/blob/master/templates/preview.html#L16), which has `method=\"post\"`\r\n* [the logs don't show a preview attempt beforehand at all.](https://console.developers.google.com/project/brid-gy/logs?service=appengine.googleapis.com&key1=default&key2=3&logName=appengine.googleapis.com%2Frequest_log&minLogLevel=0&expandAll=false&timezone=America%2FLos_Angeles&filters=text:%2Fpublish%2Fpreview)\r\n* who was this? the logs don't have anything identifying, just oauth codes and tokens. :/ the client ip is  84.255.226.221, which is t-2.net, a Slovenian ISP. the request pattern and user agent suggest that it was a human, not a bot.\r\n\r\n`/twitter/publish/start` log (all from oauth-dropins and tweepy):\r\n```\r\nCollected params: [(u'oauth_nonce', u'...'), (u'oauth_timestamp', u'1433064494'), (u'oauth_consumer_key', u'...'), (u'oauth_signature_method', u'HMAC-SHA1'), (u'oauth_version', u'1.0'), (u'oauth_callback', u'https://www.brid.gy/publish/twitter/finish')]\r\nNormalized params: oauth_callback=https%3A%2F%2Fwww.brid.gy%2Fpublish%2Ftwitter%2Ffinish&oauth_consumer_key=...&oauth_nonce=...&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1433064494&oauth_version=1.0\r\nNormalized URI: https://api.twitter.com/oauth/request_token\r\nBase signing string: POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Frequest_token&oauth_callback%3Dhttps%253A%252F%252Fwww.brid.gy%252Fpublish%252Ftwitter%252Ffinish%26oauth_consumer_key%3...%26oauth_nonce%3D...%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1433064494%26oauth_version%3D1.0\r\nSignature: ...\r\nEncoding URI, headers and body to utf-8.\r\nStarting new HTTPS connection (1): api.twitter.com\r\n\"POST /oauth/request_token HTTP/1.1\" 200 None\r\nGenerated request token, redirecting to Twitter: https://api.twitter.com/oauth/authenticate?oauth_token=...\r\nStarting OAuth flow: redirecting to https://api.twitter.com/oauth/authenticate?oauth_token=...\r\n```\r\n\r\n`/publish/twitter/finish` log (almost all from oauth-dropins and tweepy):\r\n```\r\nCollected params: [(u'oauth_nonce', u'...'), (u'oauth_timestamp', u'1433064497'), (u'oauth_verifier', u'...'), (u'oauth_consumer_key', u'...'), (u'oauth_signature_method', u'HMAC-SHA1'), (u'oauth_version', u'1.0'), (u'oauth_token', u'...')]\r\nNormalized params: oauth_consumer_key=...&oauth_nonce=...&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1433064497&oauth_token=...&oauth_verifier=...&oauth_version=1.0\r\nNormalized URI: https://api.twitter.com/oauth/access_token\r\nBase signing string: POST&https%3A%2F%2Fapi.twitter.com%2Foauth%2Faccess_token&oauth_consumer_key%3D...%26oauth_nonce%3D...%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1433064497%26oauth_token%3D...%26oauth_verifier%3D...%26oauth_version%3D1.0\r\nSignature: ...\r\nEncoding URI, headers and body to utf-8.\r\nStarting new HTTPS connection (1): api.twitter.com\r\n\"POST /oauth/access_token HTTP/1.1\" 200 None\r\nCollected params: [(u'oauth_nonce', u'...'), (u'oauth_timestamp', u'1433064497'), (u'oauth_consumer_key', u'...'), (u'oauth_signature_method', u'HMAC-SHA1'), (u'oauth_version', u'1.0'), (u'oauth_token', u'...')]\r\nNormalized params: oauth_consumer_key=...&oauth_nonce=...&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1433064497&oauth_token=...&oauth_version=1.0\r\nNormalized URI: https://api.twitter.com/1.1/account/verify_credentials.json\r\nBase signing string: GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Faccount%2Fverify_credentials.json&oauth_consumer_key%3D...%26oauth_nonce%3D...%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1433064497%26oauth_token%3D...%26oauth_version%3D1.0\r\nSignature: ...\r\nEncoding URI, headers and body to utf-8.\r\nGenerated Authorization header from access token key ... and secret ...\r\nFetching https://api.twitter.com/1.1/account/verify_credentials.json\r\ndecoding state \"\"\r\nTraceback (most recent call last):\r\n...\r\nFile \"/base/data/home/apps/s~brid-gy/3.384519463642808388/activitystreams/oauth_dropins/twitter.py\", line 98, in handle_exception\r\n    return webutil_handlers.handle_exception(self, e, debug)\r\n  File \"/base/data/home/runtimes/python27/python27_lib/versions/third_party/webapp2-2.3/webapp2.py\", line 545, in dispatch\r\n    return method(*args, **kwargs)\r\n  File \"/base/data/home/apps/s~brid-gy/3.384519463642808388/activitystreams/oauth_dropins/twitter.py\", line 196, in get\r\n    self.finish(auth, state=self.request.get('state'))\r\n  File \"/base/data/home/apps/s~brid-gy/3.384519463642808388/publish.py\", line 483, in finish\r\n    source = ndb.Key(urlsafe=self.state['source_key']).get()\r\nKeyError: 'source_key'\r\n```\r\n"}}