木匣子

Web/Game/Programming/Life etc.

「攻略」JetBrains Quest S1E1

换工作后,新的公司没有提供 Jetbrains IDE 的包年订阅。在这四个多月里,秉承入乡随俗的习惯,我跟新团队一起用 Visual Studio Code 进行项目开发。一开始非常不顺手,后来安装了各种插件并慢慢适应,勉强还能工作。虽然 VSC 也是可以将就的,但就是没有 Webstorm/Phpstorm[1] 来得爽。

Jetbrains 的 IDE 功能强大,就连内置的版本控制都比其它独立的 App 要强大得多。为了配合 VSC,我还得挑选其它的 Git 客户端来协作,先后用了 Source TreeGit KrakenFork

  • Source Tree - 免费,但是 Diff / Merge 功能不够强大,没有 fast-forward 之类的功能。
  • Git Kraken - 非常强大,前期免费,但是后来改成个人版 30 天试用,到期后开始对私有仓库收费了。
  • Fork - 免费,小清新。比 Source Tree 易用,有同分支 fast-forward 功能,但不能跨分支。

折腾了一圈,到最后还打算自费回到 JetBrains IDE 的怀抱。

来得早不如来得巧,3月9日,@JetBrains 发布了第一个挑战信,内容如下:

JetBrains Quest begins… #JetBrainsQuest
48 61 76 65 20 79 6f 75 20 73 65 65 6e 20 74 68 65 20 73 6f 75 72 63 65 20 63 6f 64 65 20 6f 66 20 74 68 65 20 4a 65 74 42 72 61 69 6e 73 20 77 65 62 73 69 74 65 3f

作为解迷爱好者,一下就精神起来了。

剧透警告!!!本文记录了挑战 I 的攻略过程。如果有兴趣自行通关,请暂时不要往下读!!!

Stage 1

观察该推文,是很常见的十六进制文本。作为一个前端开发者,我当然是用 javascript 来解题啦:

const secret = "48 61 76 65 20 79 6f 75 20 73 65 65 6e 20 74 68 65 20 73 6f 75 72 63 65 20 63 6f 64 65 20 6f 66 20 74 68 65 20 4a 65 74 42 72 61 69 6e 73 20 77 65 62 73 69 74 65 3f";
const message = secret.split(' ').map(hex => String.fromCharCode(parseInt(hex, 16))).join('');

得到解密后的信息:

"Have you seen the source code of the JetBrains website?"

Stage 2

查看 JetBrains 官网的网页源码,并搜索 quest 可以看到第二关的内容:

<!--
      O
{o)xxx|===============-
      O

Welcome to the JetBrains Quest.

What awaits ahead is a series of challenges. Each one will require a little initiative, a little thinking, and a whole lot of JetBrains to get to the end. Cheating is allowed and in some places encouraged. You have until the 15th of March at 12:00 CET to finish all the quests.
Getting to the end of each quest will earn you a reward.
Let the quest commence!

JetBrains has a lot of products, but there is one that looks like a joke on our Products page, you should start there... (hint: use Chrome Incognito mode)
It’s dangerous to go alone take this key: Good luck! == Jrrg#oxfn$

                 O
-===============|xxx(o}
                 O
-->

这里有两个重要提示:

  1. 题目的位置:在产品页有个叫 Joke(双关语)的产品;(估计刚更新不久,提示使用隐身模式避免浏览器缓存命中)
  2. 密钥(Key):Good luck! == Jrrg#oxfn$

果然在 JetBrains 产品列表 发现了一个叫 JK 的图标,点开后弹出题目:

You have discovered our JetBrains Quest! If you don’t know what this is, you should start from Twitter, Facebook or LinkedIn.

To continue to the next challenge you need to go to the following link… But there is a problem, the last 3 digits are missing:

https://jb.gg/###

To get these digits you need to know how many prime numbers there are between 500 and 5000

Good Luck!

题目中给了一个链接,但是缺少 3 个数字。这 3 个数字是 500 到 5000 范围内的所有素数个数。继续 Javascript:

const range = (n, m) => Array.from({length: m - n + 1}, (_, i) => i + n);
const isPrime = n => n===2 || !range(2, Math.sqrt(n) | 0).some(m => n % m === 0);
const count = range(500, 5000).filter(isPrime).length;

一个非常简单的 range 函数和素数判定函数,没有优化,但是够用了。算出来的结果是574。于是我们得到通往下一题的链接

Stage 3

链接跳转到了 Pycharm 的帮助文档最下面,有一张图:

PY-QUEST

图中的图标是 YouTrack,是 JetBrains 家的一款类似 Jira 的产品。他们自家的项目地址就在 YouTrack 产品页页脚的 Bug & Issue Tracker。而我们要找的是编号为 MPS-31816 的 Issue

该 Issue 内容如下:

“The key is to think back to the beginning.” – The JetBrains Quest team

Qlfh$#Li#|rx#duh#uhdglqj#wklv#|rx#pxvw#kdyh#zrunhg#rxw#krz#wr#ghfu|sw#lw1#Wklv#lv#rxu#lvvxh#wudfnhu#ghvljqhg#iru#djloh#whdpv1#Lw#lv#iuhh#iru#xs#wr#6#xvhuv#lq#Forxg#dqg#iru#43#xvhuv#lq#Vwdqgdorqh/#vr#li#|rx#zdqw#wr#jlyh#lw#d#jr#lq#|rxu#whdp#wkhq#zh#wrwdoo|#uhfrpphqg#lw1#|rx#kdyh#ilqlvkhg#wkh#iluvw#Txhvw/#qrz#lw“v#wlph#wr#uhghhp#|rxu#iluvw#sul}h1#Wkh#frgh#iru#wkh#iluvw#txhvw#lv#‟WkhGulyhWrGhyhors†1#Jr#wr#wkh#Txhvw#Sdjh#dqg#xvh#wkh#frgh#wr#fodlp#|rxu#sul}h1#kwwsv=22zzz1mhweudlqv1frp2surpr2txhvw2

这里的提示让我们回过头看看。之前有个没用过的密钥:Good luck! == Jrrg#oxfn$。熟悉经典密码学的朋友,一眼就可以看出来这里是一个对称加密的置换密钥,很可能是凯撒密码(Caesar cipher)

如果密钥中的 G === J,我们可以知道密文是由正文偏移三个字母等到 G->H->I->J,那么只要全文逆转三个字母即可得到原文。上 Javascript:

const secret = "Qlfh$#Li#|rx#duh#uhdglqj#wklv#|rx#pxvw#kdyh#zrunhg#rxw#krz#wr#ghfu|sw#lw1#Wklv#lv#rxu#lvvxh#wudfnhu#ghvljqhg#iru#djloh#whdpv1#Lw#lv#iuhh#iru#xs#wr#6#xvhuv#lq#Forxg#dqg#iru#43#xvhuv#lq#Vwdqgdorqh/#vr#li#|rx#zdqw#wr#jlyh#lw#d#jr#lq#|rxu#whdp#wkhq#zh#wrwdoo|#uhfrpphqg#lw1#|rx#kdyh#ilqlvkhg#wkh#iluvw#Txhvw/#qrz#lw“v#wlph#wr#uhghhp#|rxu#iluvw#sul}h1#Wkh#frgh#iru#wkh#iluvw#txhvw#lv#‟WkhGulyhWrGhyhors†1#Jr#wr#wkh#Txhvw#Sdjh#dqg#xvh#wkh#frgh#wr#fodlp#|rxu#sul}h1#kwwsv=22zzz1mhweudlqv1frp2surpr2txhvw2";
const message = secret.split('').map(c => String.fromCharCode(c.charCodeAt(0) - 3)).join('');

解密后得到:

"Nice! If you are reading this you must have worked out how to decrypt it. This is our issue tracker designed for agile teams. It is free for up to 3 users in Cloud and for 10 users in Standalone, so if you want to give it a go in your team then we totally recommend it. you have finished the first Quest, now it’s time to redeem your first prize. The code for the first quest is “TheDriveToDevelop”. Go to the Quest Page and use the code to claim your prize. https://www.jetbrains.com/promo/quest/"

广告打得非常溜。不过我们也得到了最后的奖励。使用兑换码TheDriveToDevelop。到该页面,即可以领取到 3 个月的 JetBrains 全线产品的订阅 License。这个页面没有对任何人进行限制,所以即使你没有进行挑战,直接进入此页面也是可以直接领奖。


Next

不得不佩服 JetBrains 的这次宣传。激活邮件中有两个彩蛋:

The next quest will be at 1583924400 on our social media.

这是第二场挑战的开题时间,即:

new Date(1583924400 * 1000).toISOString()
// UTC: "2020-03-11T11:00:00.000Z"
new Date(1583924400 * 1000).toLocaleString()
// Melbourne Local Time: "11/03/2020, 22:00:00"

还有一个用 Leet Code 写的提示(hah,注意有个拼写错误):

Y0U H4V3 R3C13V3D 7H15 3M41L B3C4U53 Y0U H4V3 P4RT1C1P4T3D 1N J3TBR41N5 QU35T

翻译过来是:

You have recieved this email because you have participated in jetbrains quest

小剧透:这个提示在第二场挑战会用到。

未完待续。


  1. Phpstorm = Webstorm + Php + Database support ↩︎