Unicode 用户名以 Σ 作为最后一个字符会导致加载个人资料页面出错

这是否也会影响与用户相关的 slug(包含用户名)?
我们有几位用户使用 UTF-8 编码的用户名,其中一些人无法访问他们的个人资料……

2 个赞

这完全不会影响用户,因为路由完全不同。

你能分享一个加载个人资料失败的链接吗?或者至少提供一个触发该 bug 的用户名示例?

4 个赞

这是一个例子:https://rembetiko.gr/u/σπυρος

用户名是 ΣΠΥΡΟΣ(即 σπυρος 的大写形式)


抱歉使用了希腊语 :sweat_smile:

2 个赞

此页面是否被 Cloudflare 代理拦截?能否关闭代理后测试一下?

另外,以下设置的值是多少:

  • 允许的 Unicode 用户名字符
  • Unicode 用户名
3 个赞

以下是这些数值(相当标准 :sweat_smile:)

是的

我刚禁用了代理并重新测试。遗憾的是,问题仍然存在。我会暂时保持代理禁用状态,以便您如果需要的话可以自行测试 :slight_smile:


非常感谢您的帮助!:smiley:

2 个赞

嗯。

如果我尝试加载大写形式,它首先会加载:https://rembetiko.gr/u/ΣΠΥΡΟΣ,随后在尝试获取小写版本的 JSON 时失败。

这看起来是我们大小写处理之间的问题。

6 个赞

奇怪的是,这个可以正常工作:

https://rembetiko.gr/u/αγγελικη_ντοτη

用户名是 ΑΓΓΕΛΙΚΗ_ΝΤΟΤΗ(即 αγγελικη_ντοτη 的大写形式)。

2 个赞

在希腊语中,字母 ‘Σ’ 是否确实有两种小写形式?

  • 当用于词尾时,写作 ‘ς’
  • 在其他位置时,写作 ‘σ’
2 个赞

那么这是错误的吗?

[1] pry(main)> "ΣΠΥΡΟΣ".downcase
=> "σπυροσ"
2 个赞

是的,从语法上讲这是错误的。正确的形式应该是“σπυρος”。

2 个赞

哦,恐怕这是一个 Ruby 的 bug:

➜  ruby --version           
ruby 3.0.0dev (2020-12-16T18:46:44Z master 93ba3ac036) [x86_64-linux]
➜  irb           
irb(main):001:0> "ΣΠΥΡΟΣ".downcase
=> "σπυροσ"
3 个赞

但当链接创建后,它却能很好地工作……所以一定有办法让它生效……(?)

https://rembetiko.gr/u/σπυρος

2 个赞

只要 Ruby 始终使用规范化后的用户名(Ruby 中的 User.normalize_username)和数据库中的 username_lower 来查找用户,那么 Ruby 是否将用户名转换为语法正确的小写版本并不重要。

哪个 JSON 请求失败了?很可能存在某个路由使用了不同的用户名比较机制。

4 个赞

也许是因为 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 列,所以也许我们依赖的是浏览器的行为?正在深入调查……

6 个赞

哦,那很糟糕。所以,问题可能出在这里:

我本来建议直接在服务器端的 UserSerializer 中添加 username_lower,而不是在客户端处理,但这仍然会留下其他几处 username.toLowerCase 的调用。

我在想,更好的解决方案是否是在服务器端使用 mini_racer 来计算包含非 ASCII 字符的 username_lower:thinking:

6 个赞

无论如何,无论我们采用哪种变通方案,我都会将此问题报告给 Ruby 团队。

8 个赞

仅供参考,PHP 的实现方式与 Ruby 相同……这让我觉得这或许是有意为之的设计?

您可以在这里测试代码:

1 个赞

有趣的是,Postgres 在这里也会失败:

[2] pry(main)> DB.query_single('select lower(?)', 'ΣΠΥΡΟΣ')
=> ["σπυροσ"]

或许我们应该在 Discourse 内部处理计算 username_lower 的方法中,专门针对这种特殊情况做处理?

找出所有调用 username_lower 的方法,将它们重定向到一个中央函数,然后在此处允许这种特殊情况(我想,如果需要的话,我们可以在这里使用 mini_racer 调用,或者简单地调用 .lower,然后使用 sub 调用进行修正)。

在此处更新原帖标题,使其更清晰。

3 个赞

给定:

[4] pry(main)> "σπυρος".downcase
=> "σπυρος"

@chrispanag 一个最简单的临时解决方案是将用户名改为 σπυρος,这样用户名和 username_lower 将完全一致,问题即可直接解决。

我个人对仅为这一特定情况在核心代码中添加临时方案持保留态度,尤其是当存在如此简单的替代方案时。

此外,你也可以通过我们的“允许的 Unicode 用户名字符”设置禁止在用户名中使用 Σ,从而确保该问题永远不会再出现。

我完全支持在此处修复 Ruby 和 Postgres 的问题,但这确实是一场需要多年努力才能解决的持久战。

5 个赞

我完全同意这一点。我们已向官方上游报告了相关缺陷,Discourse 用户在此期间可以使用现有工具进行变通处理。

5 个赞