{"action":"created","issue":{"url":"https://api.github.com/repos/jxtech/wechatpy/issues/183","repository_url":"https://api.github.com/repos/jxtech/wechatpy","labels_url":"https://api.github.com/repos/jxtech/wechatpy/issues/183/labels{/name}","comments_url":"https://api.github.com/repos/jxtech/wechatpy/issues/183/comments","events_url":"https://api.github.com/repos/jxtech/wechatpy/issues/183/events","html_url":"https://github.com/jxtech/wechatpy/issues/183","id":205555241,"node_id":"MDU6SXNzdWUyMDU1NTUyNDE=","number":183,"title":"qrconnect_url encoding issues","user":{"login":"garyhurtz","id":1086662,"node_id":"MDQ6VXNlcjEwODY2NjI=","avatar_url":"https://avatars3.githubusercontent.com/u/1086662?v=4","gravatar_id":"","url":"https://api.github.com/users/garyhurtz","html_url":"https://github.com/garyhurtz","followers_url":"https://api.github.com/users/garyhurtz/followers","following_url":"https://api.github.com/users/garyhurtz/following{/other_user}","gists_url":"https://api.github.com/users/garyhurtz/gists{/gist_id}","starred_url":"https://api.github.com/users/garyhurtz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/garyhurtz/subscriptions","organizations_url":"https://api.github.com/users/garyhurtz/orgs","repos_url":"https://api.github.com/users/garyhurtz/repos","events_url":"https://api.github.com/users/garyhurtz/events{/privacy}","received_events_url":"https://api.github.com/users/garyhurtz/received_events","type":"User","site_admin":false},"labels":[{"id":128955251,"node_id":"MDU6TGFiZWwxMjg5NTUyNTE=","url":"https://api.github.com/repos/jxtech/wechatpy/labels/bug","name":"bug","color":"fc2929","default":true},{"id":234811841,"node_id":"MDU6TGFiZWwyMzQ4MTE4NDE=","url":"https://api.github.com/repos/jxtech/wechatpy/labels/%E4%B8%BB%E5%8A%A8%E8%B0%83%E7%94%A8","name":"主动调用","color":"207de5","default":false},{"id":337327395,"node_id":"MDU6TGFiZWwzMzczMjczOTU=","url":"https://api.github.com/repos/jxtech/wechatpy/labels/%E5%85%BC%E5%AE%B9%E6%80%A7","name":"兼容性","color":"fef2c0","default":false}],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2017-02-06T11:26:54Z","updated_at":"2018-07-09T02:14:49Z","closed_at":"2017-02-19T13:03:51Z","author_association":"NONE","body":"I am using wechatpy to add wechat login capability to a website, and I found that WeChat's servers refuse to accept the URLs generated by WeChatOAuth.qrconnect_url.\r\n\r\nAfter some investigation, I found that this method does not encode URLs correctly.\r\n\r\nWeChat servers will accept the URLs after changing:\r\n\r\n        redirect_uri = quote(self.redirect_uri)\r\n\r\nto\r\n\r\n        redirect_uri = quote(self.redirect_uri, safe=u'')\r\n\r\nWanted to pass this along to the team and other users who are unable to present their users with the login QR code.\r\n-gary"},"comment":{"url":"https://api.github.com/repos/jxtech/wechatpy/issues/comments/403340438","html_url":"https://github.com/jxtech/wechatpy/issues/183#issuecomment-403340438","issue_url":"https://api.github.com/repos/jxtech/wechatpy/issues/183","id":403340438,"node_id":"MDEyOklzc3VlQ29tbWVudDQwMzM0MDQzOA==","user":{"login":"rockallite","id":2186845,"node_id":"MDQ6VXNlcjIxODY4NDU=","avatar_url":"https://avatars2.githubusercontent.com/u/2186845?v=4","gravatar_id":"","url":"https://api.github.com/users/rockallite","html_url":"https://github.com/rockallite","followers_url":"https://api.github.com/users/rockallite/followers","following_url":"https://api.github.com/users/rockallite/following{/other_user}","gists_url":"https://api.github.com/users/rockallite/gists{/gist_id}","starred_url":"https://api.github.com/users/rockallite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rockallite/subscriptions","organizations_url":"https://api.github.com/users/rockallite/orgs","repos_url":"https://api.github.com/users/rockallite/repos","events_url":"https://api.github.com/users/rockallite/events{/privacy}","received_events_url":"https://api.github.com/users/rockallite/received_events","type":"User","site_admin":false},"created_at":"2018-07-09T02:14:49Z","updated_at":"2018-07-09T02:14:49Z","author_association":"NONE","body":"@messense For Python 2.7, commit https://github.com/jxtech/wechatpy/commit/3610e8112fbee2d224c11b961ec73ea3ce65e0af introduce a new problem: cache pollution in `quote()`. It causes `UnicodeDecodeError` in subsequent calls to `quote()` with a non-ascii value, if any function in wechatpy which involves in calling `quote(..., safe='')` (the `safe` parameter is a unicode) gets called first in a Python process.\r\n\r\nI can confirm that this bug still exists in wechatpy 1.7.4.\r\n\r\nFor example, after starting a Django dev server, first make an OAuth request in WeChat devtools, then make a fuzzy search with non-ascii characters in Django admin. A typical traceback would look like this:\r\n\r\n```\r\n  ...\r\n  File \"/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py\", line 1297, in quote\r\n    if not s.rstrip(safe):\r\nUnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)\r\n```\r\n\r\nThe corresponding interactive traceback view in Django would look like this:\r\n\r\n```\r\n...\r\n/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py in quote\r\n1290.         (quoter, safe) = _safe_quoters[cachekey]\r\n1291.     except KeyError:\r\n1292.         safe_map = _safe_map.copy()\r\n1293.         safe_map.update([(c, c) for c in safe])\r\n1294.         quoter = safe_map.__getitem__\r\n1295.         safe = always_safe + safe\r\n1296.         _safe_quoters[cachekey] = (quoter, safe)\r\n1297.     if not s.rstrip(safe): ...\r\n1298.         return s\r\n1299.     return ''.join(map(quoter, s))\r\n1300.\r\n1301. def quote_plus(s, safe=''):\r\n1302.     \"\"\"Quote the query fragment of a URL; replacing ' ' with '+'\"\"\"\r\n1303.     if ' ' in s:\r\n\r\nLocal vars\r\nVariable | Value\r\n      -- | --\r\ncachekey | ('', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.-')\r\n  quoter | <built-in method __getitem__ of dict object at 0x10e5b4d70>\r\n       s | '\\xe4\\xb8\\xad'\r\n    safe | u'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.-'\r\n```\r\n\r\nAs you can see, the `safe` variable from `_safe_quoters` dict (as a cache) becomes a unicode string, which ought to be a byte string.\r\n\r\nIf you make the fuzzy search in Django admin first, everything is fine.\r\n\r\nThe proper fix in wechatpy should be calling `quote` with byte strings, like this: `quote(self.redirect_url, safe=b'')` (because of the `from __future__ import unicode_literals` statement at the top of a file).\r\n\r\nA temporary fix in an existing (Python 2.7) project would be calling the following code in a bootstrap script, so the `quote()` cache is filled with a proper value:\r\n\r\n```\r\nfrom urllib import quote\r\n\r\n\r\nquote('non-empty-string', safe='')\r\n```\r\n\r\nA good place for a Django project would be `<project_name>/__init__.py`."}}
{"actor":{"display_login":"rockallite"}}