这是否也会影响与用户相关的 slug(包含用户名)?
我们有几位用户使用 UTF-8 编码的用户名,其中一些人无法访问他们的个人资料……
这完全不会影响用户,因为路由完全不同。
你能分享一个加载个人资料失败的链接吗?或者至少提供一个触发该 bug 的用户名示例?
此页面是否被 Cloudflare 代理拦截?能否关闭代理后测试一下?
另外,以下设置的值是多少:
允许的 Unicode 用户名字符Unicode 用户名
在希腊语中,字母 ‘Σ’ 是否确实有两种小写形式?
- 当用于词尾时,写作 ‘ς’
- 在其他位置时,写作 ‘σ’
那么这是错误的吗?
[1] pry(main)> "ΣΠΥΡΟΣ".downcase
=> "σπυροσ"
是的,从语法上讲这是错误的。正确的形式应该是“σπυρος”。
哦,恐怕这是一个 Ruby 的 bug:
➜ ruby --version
ruby 3.0.0dev (2020-12-16T18:46:44Z master 93ba3ac036) [x86_64-linux]
➜ irb
irb(main):001:0> "ΣΠΥΡΟΣ".downcase
=> "σπυροσ"
但当链接创建后,它却能很好地工作……所以一定有办法让它生效……(?)
只要 Ruby 始终使用规范化后的用户名(Ruby 中的 User.normalize_username)和数据库中的 username_lower 来查找用户,那么 Ruby 是否将用户名转换为语法正确的小写版本并不重要。
哪个 JSON 请求失败了?很可能存在某个路由使用了不同的用户名比较机制。
也许是因为 Ruby 和 JavaScript 的实现方式不同?
➜ ruby --version
ruby 3.0.0dev (2020-12-16T18:46:44Z master 93ba3ac036) [x86_64-linux]
➜ irb
irb(main):001:0> "ΣΠΥΡΟΣ".downcase
=> "σπυροσ"
➜ node
Welcome to Node.js v12.11.1.
Type ".help" for more information.
> "ΣΠΥΡΟΣ".toLowerCase()
'σπυρος'
在我的测试中,Firefox 的表现与 NodeJS 一致。
端点 /u/#{username}.json 只返回了 username 列,而没有返回 username_lower 列,所以也许我们依赖的是浏览器的行为?正在深入调查……
哦,那很糟糕。所以,问题可能出在这里:
我本来建议直接在服务器端的 UserSerializer 中添加 username_lower,而不是在客户端处理,但这仍然会留下其他几处 username.toLowerCase 的调用。
我在想,更好的解决方案是否是在服务器端使用 mini_racer 来计算包含非 ASCII 字符的 username_lower。![]()
无论如何,无论我们采用哪种变通方案,我都会将此问题报告给 Ruby 团队。
仅供参考,PHP 的实现方式与 Ruby 相同……这让我觉得这或许是有意为之的设计?
您可以在这里测试代码:
有趣的是,Postgres 在这里也会失败:
[2] pry(main)> DB.query_single('select lower(?)', 'ΣΠΥΡΟΣ')
=> ["σπυροσ"]
或许我们应该在 Discourse 内部处理计算 username_lower 的方法中,专门针对这种特殊情况做处理?
找出所有调用 username_lower 的方法,将它们重定向到一个中央函数,然后在此处允许这种特殊情况(我想,如果需要的话,我们可以在这里使用 mini_racer 调用,或者简单地调用 .lower,然后使用 sub 调用进行修正)。
在此处更新原帖标题,使其更清晰。
给定:
[4] pry(main)> "σπυρος".downcase
=> "σπυρος"
@chrispanag 一个最简单的临时解决方案是将用户名改为 σπυρος,这样用户名和 username_lower 将完全一致,问题即可直接解决。
我个人对仅为这一特定情况在核心代码中添加临时方案持保留态度,尤其是当存在如此简单的替代方案时。
此外,你也可以通过我们的“允许的 Unicode 用户名字符”设置禁止在用户名中使用 Σ,从而确保该问题永远不会再出现。
我完全支持在此处修复 Ruby 和 Postgres 的问题,但这确实是一场需要多年努力才能解决的持久战。
我完全同意这一点。我们已向官方上游报告了相关缺陷,Discourse 用户在此期间可以使用现有工具进行变通处理。
