{"action":"opened","number":642,"pull_request":{"url":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls/642","id":88625390,"html_url":"https://github.com/shadowsocks/shadowsocks/pull/642","diff_url":"https://github.com/shadowsocks/shadowsocks/pull/642.diff","patch_url":"https://github.com/shadowsocks/shadowsocks/pull/642.patch","issue_url":"https://api.github.com/repos/shadowsocks/shadowsocks/issues/642","number":642,"state":"open","locked":false,"title":"Fix a OTA bug on `_ota_chunk_data`","user":{"login":"loggerhead","id":5056390,"avatar_url":"https://avatars.githubusercontent.com/u/5056390?v=3","gravatar_id":"","url":"https://api.github.com/users/loggerhead","html_url":"https://github.com/loggerhead","followers_url":"https://api.github.com/users/loggerhead/followers","following_url":"https://api.github.com/users/loggerhead/following{/other_user}","gists_url":"https://api.github.com/users/loggerhead/gists{/gist_id}","starred_url":"https://api.github.com/users/loggerhead/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/loggerhead/subscriptions","organizations_url":"https://api.github.com/users/loggerhead/orgs","repos_url":"https://api.github.com/users/loggerhead/repos","events_url":"https://api.github.com/users/loggerhead/events{/privacy}","received_events_url":"https://api.github.com/users/loggerhead/received_events","type":"User","site_admin":false},"body":"You can repro it by following code:\r\n\r\n```python\r\nfrom __future__ import print_function\r\nimport struct\r\n\r\nONETIMEAUTH_BYTES = 10\r\nONETIMEAUTH_CHUNK_BYTES = 12\r\nONETIMEAUTH_CHUNK_DATA_LEN = 2\r\n\r\nclass OTA(object):\r\n    def __init__(self):\r\n        self._ota_len = 0\r\n        self._ota_chunk_idx = 0\r\n        self._ota_buff_head = b''\r\n        self._ota_buff_data = b''\r\n\r\n    def _ota_chunk_data(self, data, data_cb):\r\n        # spec https://shadowsocks.org/en/spec/one-time-auth.html\r\n        unchunk_data = b''\r\n        while len(data) > 0:\r\n            if self._ota_len == 0:\r\n                # get DATA.LEN + HMAC-SHA1\r\n                length = ONETIMEAUTH_CHUNK_BYTES - len(self._ota_buff_head)\r\n                self._ota_buff_head += data[:length]\r\n                data = data[length:]\r\n                if len(self._ota_buff_head) < ONETIMEAUTH_CHUNK_BYTES:\r\n                    # wait more data\r\n                    return\r\n                data_len = self._ota_buff_head[:ONETIMEAUTH_CHUNK_DATA_LEN]\r\n                self._ota_len = struct.unpack('>H', data_len)[0]\r\n            length = min(self._ota_len, len(data))\r\n            self._ota_buff_data += data[:length]\r\n            data = data[length:]\r\n            if len(self._ota_buff_data) == self._ota_len:\r\n                # get a chunk data\r\n                _hash = self._ota_buff_head[ONETIMEAUTH_CHUNK_DATA_LEN:]\r\n                _data = self._ota_buff_data\r\n                index = struct.pack('>I', self._ota_chunk_idx)\r\n                # key = self._encryptor.decipher_iv + index\r\n                # if onetimeauth_verify(_hash, _data, key) is False:\r\n                #     logging.warn('one time auth fail, drop chunk !')\r\n                # else:\r\n                unchunk_data += _data\r\n                self._ota_chunk_idx += 1\r\n\r\n                self._ota_buff_head = b''\r\n                self._ota_buff_data = b''\r\n                self._ota_len = 0\r\n        data_cb(unchunk_data)\r\n        return\r\n\r\n\r\ndef test(data):\r\n    print(\"-\" * 40)\r\n    o = OTA()\r\n    for frag in data:\r\n        o._ota_chunk_data(frag, print)\r\n\r\nif __name__ == '__main__':\r\n    data1 = [\r\n        b'\\x00\\x03hhhhhhhhhh111\\x00\\x03hhhhhhhhhh222',\r\n    ]\r\n    data2 = [\r\n        b'\\x00\\x03hhhhhhhhhh1',\r\n        b'11\\x00\\x03hhhhhhhhhh222',\r\n    ]\r\n\r\n    test(data1)\r\n    test(data2)\r\n```\r\n\r\nThe output:\r\n\r\n```\r\n----------------------------------------\r\n111222\r\n----------------------------------------\r\n\r\n\r\n```","created_at":"2016-10-10T08:30:48Z","updated_at":"2016-10-10T08:30:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls/642/commits","review_comments_url":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls/642/comments","review_comment_url":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls/comments{/number}","comments_url":"https://api.github.com/repos/shadowsocks/shadowsocks/issues/642/comments","statuses_url":"https://api.github.com/repos/shadowsocks/shadowsocks/statuses/50427c607594b3a2c12900e7a705e9f9b0762241","head":{"label":"loggerhead:loggerhead","ref":"loggerhead","sha":"50427c607594b3a2c12900e7a705e9f9b0762241","user":{"login":"loggerhead","id":5056390,"avatar_url":"https://avatars.githubusercontent.com/u/5056390?v=3","gravatar_id":"","url":"https://api.github.com/users/loggerhead","html_url":"https://github.com/loggerhead","followers_url":"https://api.github.com/users/loggerhead/followers","following_url":"https://api.github.com/users/loggerhead/following{/other_user}","gists_url":"https://api.github.com/users/loggerhead/gists{/gist_id}","starred_url":"https://api.github.com/users/loggerhead/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/loggerhead/subscriptions","organizations_url":"https://api.github.com/users/loggerhead/orgs","repos_url":"https://api.github.com/users/loggerhead/repos","events_url":"https://api.github.com/users/loggerhead/events{/privacy}","received_events_url":"https://api.github.com/users/loggerhead/received_events","type":"User","site_admin":false},"repo":{"id":70464009,"name":"shadowsocks","full_name":"loggerhead/shadowsocks","owner":{"login":"loggerhead","id":5056390,"avatar_url":"https://avatars.githubusercontent.com/u/5056390?v=3","gravatar_id":"","url":"https://api.github.com/users/loggerhead","html_url":"https://github.com/loggerhead","followers_url":"https://api.github.com/users/loggerhead/followers","following_url":"https://api.github.com/users/loggerhead/following{/other_user}","gists_url":"https://api.github.com/users/loggerhead/gists{/gist_id}","starred_url":"https://api.github.com/users/loggerhead/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/loggerhead/subscriptions","organizations_url":"https://api.github.com/users/loggerhead/orgs","repos_url":"https://api.github.com/users/loggerhead/repos","events_url":"https://api.github.com/users/loggerhead/events{/privacy}","received_events_url":"https://api.github.com/users/loggerhead/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/loggerhead/shadowsocks","description":null,"fork":true,"url":"https://api.github.com/repos/loggerhead/shadowsocks","forks_url":"https://api.github.com/repos/loggerhead/shadowsocks/forks","keys_url":"https://api.github.com/repos/loggerhead/shadowsocks/keys{/key_id}","collaborators_url":"https://api.github.com/repos/loggerhead/shadowsocks/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/loggerhead/shadowsocks/teams","hooks_url":"https://api.github.com/repos/loggerhead/shadowsocks/hooks","issue_events_url":"https://api.github.com/repos/loggerhead/shadowsocks/issues/events{/number}","events_url":"https://api.github.com/repos/loggerhead/shadowsocks/events","assignees_url":"https://api.github.com/repos/loggerhead/shadowsocks/assignees{/user}","branches_url":"https://api.github.com/repos/loggerhead/shadowsocks/branches{/branch}","tags_url":"https://api.github.com/repos/loggerhead/shadowsocks/tags","blobs_url":"https://api.github.com/repos/loggerhead/shadowsocks/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/loggerhead/shadowsocks/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/loggerhead/shadowsocks/git/refs{/sha}","trees_url":"https://api.github.com/repos/loggerhead/shadowsocks/git/trees{/sha}","statuses_url":"https://api.github.com/repos/loggerhead/shadowsocks/statuses/{sha}","languages_url":"https://api.github.com/repos/loggerhead/shadowsocks/languages","stargazers_url":"https://api.github.com/repos/loggerhead/shadowsocks/stargazers","contributors_url":"https://api.github.com/repos/loggerhead/shadowsocks/contributors","subscribers_url":"https://api.github.com/repos/loggerhead/shadowsocks/subscribers","subscription_url":"https://api.github.com/repos/loggerhead/shadowsocks/subscription","commits_url":"https://api.github.com/repos/loggerhead/shadowsocks/commits{/sha}","git_commits_url":"https://api.github.com/repos/loggerhead/shadowsocks/git/commits{/sha}","comments_url":"https://api.github.com/repos/loggerhead/shadowsocks/comments{/number}","issue_comment_url":"https://api.github.com/repos/loggerhead/shadowsocks/issues/comments{/number}","contents_url":"https://api.github.com/repos/loggerhead/shadowsocks/contents/{+path}","compare_url":"https://api.github.com/repos/loggerhead/shadowsocks/compare/{base}...{head}","merges_url":"https://api.github.com/repos/loggerhead/shadowsocks/merges","archive_url":"https://api.github.com/repos/loggerhead/shadowsocks/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/loggerhead/shadowsocks/downloads","issues_url":"https://api.github.com/repos/loggerhead/shadowsocks/issues{/number}","pulls_url":"https://api.github.com/repos/loggerhead/shadowsocks/pulls{/number}","milestones_url":"https://api.github.com/repos/loggerhead/shadowsocks/milestones{/number}","notifications_url":"https://api.github.com/repos/loggerhead/shadowsocks/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/loggerhead/shadowsocks/labels{/name}","releases_url":"https://api.github.com/repos/loggerhead/shadowsocks/releases{/id}","deployments_url":"https://api.github.com/repos/loggerhead/shadowsocks/deployments","created_at":"2016-10-10T07:43:40Z","updated_at":"2016-10-10T08:20:06Z","pushed_at":"2016-10-10T08:19:59Z","git_url":"git://github.com/loggerhead/shadowsocks.git","ssh_url":"git@github.com:loggerhead/shadowsocks.git","clone_url":"https://github.com/loggerhead/shadowsocks.git","svn_url":"https://github.com/loggerhead/shadowsocks","homepage":"","size":1848,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"loggerhead"}},"base":{"label":"shadowsocks:master","ref":"master","sha":"5cd9f04948c6a46bf3af75577a2225bff9ebc9f1","user":{"login":"shadowsocks","id":3006190,"avatar_url":"https://avatars.githubusercontent.com/u/3006190?v=3","gravatar_id":"","url":"https://api.github.com/users/shadowsocks","html_url":"https://github.com/shadowsocks","followers_url":"https://api.github.com/users/shadowsocks/followers","following_url":"https://api.github.com/users/shadowsocks/following{/other_user}","gists_url":"https://api.github.com/users/shadowsocks/gists{/gist_id}","starred_url":"https://api.github.com/users/shadowsocks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shadowsocks/subscriptions","organizations_url":"https://api.github.com/users/shadowsocks/orgs","repos_url":"https://api.github.com/users/shadowsocks/repos","events_url":"https://api.github.com/users/shadowsocks/events{/privacy}","received_events_url":"https://api.github.com/users/shadowsocks/received_events","type":"Organization","site_admin":false},"repo":{"id":4086616,"name":"shadowsocks","full_name":"shadowsocks/shadowsocks","owner":{"login":"shadowsocks","id":3006190,"avatar_url":"https://avatars.githubusercontent.com/u/3006190?v=3","gravatar_id":"","url":"https://api.github.com/users/shadowsocks","html_url":"https://github.com/shadowsocks","followers_url":"https://api.github.com/users/shadowsocks/followers","following_url":"https://api.github.com/users/shadowsocks/following{/other_user}","gists_url":"https://api.github.com/users/shadowsocks/gists{/gist_id}","starred_url":"https://api.github.com/users/shadowsocks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shadowsocks/subscriptions","organizations_url":"https://api.github.com/users/shadowsocks/orgs","repos_url":"https://api.github.com/users/shadowsocks/repos","events_url":"https://api.github.com/users/shadowsocks/events{/privacy}","received_events_url":"https://api.github.com/users/shadowsocks/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/shadowsocks/shadowsocks","description":"","fork":false,"url":"https://api.github.com/repos/shadowsocks/shadowsocks","forks_url":"https://api.github.com/repos/shadowsocks/shadowsocks/forks","keys_url":"https://api.github.com/repos/shadowsocks/shadowsocks/keys{/key_id}","collaborators_url":"https://api.github.com/repos/shadowsocks/shadowsocks/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/shadowsocks/shadowsocks/teams","hooks_url":"https://api.github.com/repos/shadowsocks/shadowsocks/hooks","issue_events_url":"https://api.github.com/repos/shadowsocks/shadowsocks/issues/events{/number}","events_url":"https://api.github.com/repos/shadowsocks/shadowsocks/events","assignees_url":"https://api.github.com/repos/shadowsocks/shadowsocks/assignees{/user}","branches_url":"https://api.github.com/repos/shadowsocks/shadowsocks/branches{/branch}","tags_url":"https://api.github.com/repos/shadowsocks/shadowsocks/tags","blobs_url":"https://api.github.com/repos/shadowsocks/shadowsocks/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/shadowsocks/shadowsocks/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/shadowsocks/shadowsocks/git/refs{/sha}","trees_url":"https://api.github.com/repos/shadowsocks/shadowsocks/git/trees{/sha}","statuses_url":"https://api.github.com/repos/shadowsocks/shadowsocks/statuses/{sha}","languages_url":"https://api.github.com/repos/shadowsocks/shadowsocks/languages","stargazers_url":"https://api.github.com/repos/shadowsocks/shadowsocks/stargazers","contributors_url":"https://api.github.com/repos/shadowsocks/shadowsocks/contributors","subscribers_url":"https://api.github.com/repos/shadowsocks/shadowsocks/subscribers","subscription_url":"https://api.github.com/repos/shadowsocks/shadowsocks/subscription","commits_url":"https://api.github.com/repos/shadowsocks/shadowsocks/commits{/sha}","git_commits_url":"https://api.github.com/repos/shadowsocks/shadowsocks/git/commits{/sha}","comments_url":"https://api.github.com/repos/shadowsocks/shadowsocks/comments{/number}","issue_comment_url":"https://api.github.com/repos/shadowsocks/shadowsocks/issues/comments{/number}","contents_url":"https://api.github.com/repos/shadowsocks/shadowsocks/contents/{+path}","compare_url":"https://api.github.com/repos/shadowsocks/shadowsocks/compare/{base}...{head}","merges_url":"https://api.github.com/repos/shadowsocks/shadowsocks/merges","archive_url":"https://api.github.com/repos/shadowsocks/shadowsocks/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/shadowsocks/shadowsocks/downloads","issues_url":"https://api.github.com/repos/shadowsocks/shadowsocks/issues{/number}","pulls_url":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls{/number}","milestones_url":"https://api.github.com/repos/shadowsocks/shadowsocks/milestones{/number}","notifications_url":"https://api.github.com/repos/shadowsocks/shadowsocks/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/shadowsocks/shadowsocks/labels{/name}","releases_url":"https://api.github.com/repos/shadowsocks/shadowsocks/releases{/id}","deployments_url":"https://api.github.com/repos/shadowsocks/shadowsocks/deployments","created_at":"2012-04-20T13:10:49Z","updated_at":"2016-10-10T08:04:20Z","pushed_at":"2016-10-10T08:30:48Z","git_url":"git://github.com/shadowsocks/shadowsocks.git","ssh_url":"git@github.com:shadowsocks/shadowsocks.git","clone_url":"https://github.com/shadowsocks/shadowsocks.git","svn_url":"https://github.com/shadowsocks/shadowsocks","homepage":"","size":1848,"stargazers_count":14664,"watchers_count":14664,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":9196,"mirror_url":null,"open_issues_count":65,"forks":9196,"open_issues":65,"watchers":14664,"default_branch":"rm"}},"_links":{"self":{"href":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls/642"},"html":{"href":"https://github.com/shadowsocks/shadowsocks/pull/642"},"issue":{"href":"https://api.github.com/repos/shadowsocks/shadowsocks/issues/642"},"comments":{"href":"https://api.github.com/repos/shadowsocks/shadowsocks/issues/642/comments"},"review_comments":{"href":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls/642/comments"},"review_comment":{"href":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/shadowsocks/shadowsocks/pulls/642/commits"},"statuses":{"href":"https://api.github.com/repos/shadowsocks/shadowsocks/statuses/50427c607594b3a2c12900e7a705e9f9b0762241"}},"merged":false,"mergeable":null,"mergeable_state":"unknown","merged_by":null,"comments":0,"review_comments":0,"commits":1,"additions":1,"deletions":1,"changed_files":1}}
{"actor":{"display_login":"loggerhead"}}