chore(i18n,learn): processed translations (#45504)
This commit is contained in:
@@ -16,7 +16,7 @@ dashedName: anonymous-message-board
|
||||
- 使用 [我们的 Replit 启动项目](https://replit.com/github/freeCodeCamp/boilerplate-project-messageboard)来完成你的项目。
|
||||
- 使用一个你喜欢的站点生成器来完成项目。 需要确定包含了我们 GitHub 仓库的所有文件。
|
||||
|
||||
完成本项目后,请将一个正常运行的 demo(项目演示)托管在可以公开访问的平台。 然后将 URL 提交到 `Solution Link` 中。 此外,还可以将项目的源码提交到 `GitHub Link` 中。
|
||||
完成本项目后,请将一个正常运行的 demo(项目演示)托管在可以公开访问的平台。 然后将 URL 提交到 `Solution Link` 中。 此外,还可以提交一个指向项目源码的 `GitHub Link`。
|
||||
|
||||
# --instructions--
|
||||
|
||||
@@ -116,49 +116,270 @@ async (getUserInput) => {
|
||||
你可以向 `/api/replies/{board}` 发送一个 POST 请求,其中包括字段 `text`、`delete_password` & `thread_id`。 这将更新 `bumped_on` 日期到评论日期。 在主题的 `replies` 数组中,将保存一个对象,至少有 `_id`、`text`、`created_on`、`delete_password`、& `reported` 这些属性。
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const body = await fetch(url + '/api/threads/fcc_test');
|
||||
const thread = await body.json();
|
||||
|
||||
const date = new Date();
|
||||
const text = `fcc_test_reply_${date}`;
|
||||
const delete_password = 'delete_me';
|
||||
const thread_id = thread[0]._id;
|
||||
const replyCount = thread[0].replies.length;
|
||||
|
||||
const data = { text, delete_password, thread_id };
|
||||
const res = await fetch(url + '/api/replies/fcc_test', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
if (res.ok) {
|
||||
const checkData = await fetch(`${url}/api/replies/fcc_test?thread_id=${thread_id}`);
|
||||
const parsed = await checkData.json();
|
||||
try {
|
||||
assert.equal(parsed.replies.length, replyCount + 1);
|
||||
assert.equal(parsed.replies[0].text, text);
|
||||
assert.equal(parsed._id, thread_id);
|
||||
assert.equal(parsed.bumped_on, parsed.replies[0].created_on);
|
||||
} catch (err) {
|
||||
throw new Error(err.responseText || err.message);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
你可以向 `/api/threads/{board}` 发送一个 GET 请求。 返回的将是一个数组,包括论坛上最近的 10 个被回复的主题,及每个主题最新的 3 个回帖。 `reported` 和 `delete_password` 字段将不会被发送到客户端。
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
const res = await fetch(url + '/api/threads/fcc_test');
|
||||
|
||||
if (res.ok) {
|
||||
const threads = await res.json();
|
||||
try {
|
||||
assert.equal(res.status, 200);
|
||||
assert.isAtMost(threads.length, 10);
|
||||
for (let i = 0; i < threads.length; i++) {
|
||||
assert.containsAllKeys(threads[i], ["_id", "text", "created_on", "bumped_on", "replies"]);
|
||||
assert.isAtMost(threads[i].replies.length, 3);
|
||||
assert.notExists(threads[i].delete_password);
|
||||
assert.notExists(threads[i].reported);
|
||||
for (let j = 0; j < threads[i].replies.length; j++) {
|
||||
assert.notExists(threads[i].replies[j].delete_password);
|
||||
assert.notExists(threads[i].replies[j].reported);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(err.responseText || err.message);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
你可以向 `/api/replies/{board}?thread_id={thread_id}` 发送一个 GET 请求。 返回的将是带有所有的回复的整个主题,不包括与之前测试相同的客户端字段。
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
let res = await fetch(url + '/api/threads/fcc_test');
|
||||
const threads = await res.json();
|
||||
const thread_id = threads[0]._id;
|
||||
res = await fetch(`${url}/api/replies/fcc_test?thread_id=${thread_id}`);
|
||||
|
||||
if (res.ok) {
|
||||
const thread = await res.json();
|
||||
try {
|
||||
assert.equal(res.status, 200);
|
||||
assert.isObject(thread);
|
||||
assert.containsAllKeys(thread, ["_id", "text", "created_on", "bumped_on", "replies"]);
|
||||
assert.isArray(thread.replies);
|
||||
assert.notExists(thread.delete_password);
|
||||
assert.notExists(thread.reported);
|
||||
for (let i = 0; i < thread.replies.length; i++) {
|
||||
assert.notExists(thread.replies[i].delete_password);
|
||||
assert.notExists(thread.replies[i].reported);
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(err.responseText || err.message);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
你可以向 `/api/threads/{board}` 发送一个 DELETE 请求,并传递 `thread_id` & `delete_password` 来删除该线程。 返回的将是字符串 `incorrect password` 或 `success`。
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
let res = await fetch(url + '/api/threads/fcc_test');
|
||||
const threads = await res.json();
|
||||
const thread_id = threads[0]._id;
|
||||
let data = { thread_id, delete_password: "wrong_password" };
|
||||
const res_invalid = await fetch(url + '/api/threads/fcc_test', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
data = { thread_id, delete_password: "delete_me" };
|
||||
res = await fetch(url + '/api/threads/fcc_test', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const deleted = await res.text();
|
||||
const not_deleted = await res_invalid.text();
|
||||
try {
|
||||
assert.equal(res.status, 200);
|
||||
assert.equal(deleted, "success");
|
||||
assert.equal(not_deleted, "incorrect password");
|
||||
} catch (err) {
|
||||
throw new Error(err.responseText || err.message);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
你可以向 `/api/replies/{board}` 发送一个 DELETE 请求,并传递 `thread_id`、`reply_id`、& `delete_password`。 返回的将是字符串 `incorrect password` 或 `success`。 成功后,`reply_id` 的文本将更改为 `[deleted]`。
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
|
||||
const thread_data = {
|
||||
text: "fcc_test_thread",
|
||||
delete_password: "delete_me",
|
||||
};
|
||||
await fetch(`${url}/api/threads/fcc_test`, {
|
||||
method: "POST",
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(thread_data)
|
||||
});
|
||||
let res = await fetch(`${url}/api/threads/fcc_test`);
|
||||
let threads = await res.json();
|
||||
const thread_id = threads[0]._id;
|
||||
|
||||
const reply_data = { thread_id, text: "fcc_test_reply", delete_password: "delete_me" };
|
||||
await fetch(`${url}/api/replies/fcc_test`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(reply_data)
|
||||
});
|
||||
res = await fetch(`${url}/api/threads/fcc_test`);
|
||||
threads = await res.json();
|
||||
const reply_id = threads[0].replies[0]._id;
|
||||
|
||||
const data = { thread_id, reply_id, delete_password: "delete_me" };
|
||||
res = await fetch(url + '/api/replies/fcc_test', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const deleted = await res.text();
|
||||
try {
|
||||
assert.equal(res.status, 200);
|
||||
assert.equal(deleted, "success");
|
||||
res = await fetch(`${url}/api/replies/fcc_test?thread_id=${thread_id}`);
|
||||
const thread = await res.json();
|
||||
assert.equal(thread._id, thread_id);
|
||||
assert.equal(thread.replies[0]._id, reply_id);
|
||||
assert.equal(thread.replies[0].text, "[deleted]");
|
||||
} catch (err) {
|
||||
throw new Error(err.responseText || err.message);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
你可以向 `/api/threads/{board}` 发送一个 PUT 请求,并传递 `thread_id`。 返回的将是字符串 `success`。 `thread_id` 回复的 `reported` 值将改为 `true`。
|
||||
你可以向 `/api/threads/{board}` 发送一个 PUT 请求,并传递 `thread_id`。 返回的将是字符串 `reported`。 `thread_id` 回复的 `reported` 值将改为 `true`。
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
|
||||
let res = await fetch(`${url}/api/threads/fcc_test`);
|
||||
const threads = await res.json();
|
||||
const report_id = threads[0]._id;
|
||||
const data = { report_id };
|
||||
|
||||
res = await fetch(`${url}/api/threads/fcc_test`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const reported = await res.text();
|
||||
try {
|
||||
assert.equal(res.status, 200);
|
||||
assert.equal(reported, "reported");
|
||||
} catch (err) {
|
||||
throw new Error(err.responseText || err.message);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
你可以通过向 `/api/replies/{board}` 发送 PUT 请求并传递 `thread_id` & `reply_id`。 返回的将是字符串 `success`。 `reply_id` 的 `reported` 值将被改变为 `true`。
|
||||
你可以通过向 `/api/replies/{board}` 发送 PUT 请求并传递 `thread_id` & `reply_id`。 返回的将是字符串 `reported`。 `reply_id` 的 `reported` 值将被改变为 `true`。
|
||||
|
||||
```js
|
||||
async (getUserInput) => {
|
||||
const url = getUserInput('url');
|
||||
|
||||
let res = await fetch(`${url}/api/threads/fcc_test`);
|
||||
const threads = await res.json();
|
||||
const thread_id = threads[0]._id;
|
||||
const reply_id = threads[0].replies[0]._id;
|
||||
const data = { thread_id, reply_id };
|
||||
|
||||
res = await fetch(`${url}/api/replies/fcc_test`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const reported = await res.text();
|
||||
try {
|
||||
assert.equal(res.status, 200);
|
||||
assert.equal(reported, "reported");
|
||||
} catch (err) {
|
||||
throw new Error(err.responseText || err.message);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`${res.status} ${res.statusText}`);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
所有 10 项功能测试都已完成并通过。
|
||||
|
||||
```js
|
||||
|
||||
async (getUserInput) => {
|
||||
const tests = await fetch(getUserInput('url') + '/_api/get-tests');
|
||||
const parsed = await tests.json();
|
||||
assert.isTrue(parsed.length >= 10);
|
||||
parsed.forEach((test) => {
|
||||
assert.equal(test.state, 'passed');
|
||||
assert.isAtLeast(test.assertions.length, 1);
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
@@ -9,22 +9,74 @@ dashedName: port-scanner
|
||||
|
||||
# --description--
|
||||
|
||||
你将通过使用我们的 [Replit 入门代码](https://replit.com/github/freeCodeCamp/boilerplate-port-scanner) 来完成本项目。
|
||||
|
||||
我们仍在开发 Python 课程的交互式教学部分。 目前,你可以在 YouTube 上通过 freeCodeCamp.org 上传的一些视频学习这个项目相关的知识。
|
||||
|
||||
- [Python for Everybody 视频课程](https://www.freecodecamp.org/news/python-for-everybody/)(14 小时)
|
||||
|
||||
- [Learn Python 视频课程](https://www.freecodecamp.org/news/learn-python-video-course/)(10 小时)
|
||||
|
||||
# --instructions--
|
||||
|
||||
使用 Python 创建一个端口扫描器。
|
||||
|
||||
你可以访问 [Replit 上的完整项目描述和启动代码](https://replit.com/github/freeCodeCamp/boilerplate-port-scanner)。
|
||||
在 `port_scanner.py` 文件中,创建一个名为 `get_open_ports` 的函数,它接受一个 `target` 参数和一个 `port_range` 参数。 `target` 可以是 URL 或 IP 地址。 `port_range` 是两个数字的列表,表示要检查的端口范围的第一个和最后一个数字。
|
||||
|
||||
在打开链接之后 fork 该项目。 根据 “README.md” 中的指示完成整个项目,然后在下面提交你的项目链接。
|
||||
以下是如何调用该函数的示例:
|
||||
|
||||
Python 课程的交互式教学部分仍在开发当中。 目前,freeCodeCamp YouTube 频道上的一些视频将会教授你这个项目要求的一些 Python 技能。
|
||||
```py
|
||||
get_open_ports("209.216.230.240", [440, 445])
|
||||
get_open_ports("www.stackoverflow.com", [79, 82])
|
||||
```
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href='https://www.freecodecamp.org/news/python-for-everybody/'>Python for Everybody 视频课程</a>(14 小时)
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://www.freecodecamp.org/news/learn-python-basics-in-depth-video-course/'>Learn Python 视频课程</a>(2 小时)
|
||||
</li>
|
||||
</ul>
|
||||
该函数应返回给定范围内的开放端口列表。
|
||||
|
||||
`get_open_ports` 函数还应采用可选的第三个参数 `True` 来表示“详细”模式。 如果将其设置为 true,则该函数应返回描述性字符串而不是端口列表。
|
||||
|
||||
以下是详细模式下应返回的字符串格式(`{}` 中的文本表示应显示的信息):
|
||||
|
||||
```bash
|
||||
Open ports for {URL} ({IP address})
|
||||
PORT SERVICE
|
||||
{port} {service name}
|
||||
{port} {service name}
|
||||
```
|
||||
|
||||
你可以使用 `common_ports.py` 中的字典为每个端口获取正确的服务名称。
|
||||
|
||||
例如,如果函数是这样调用的:
|
||||
|
||||
```py
|
||||
port_scanner.get_open_ports("scanme.nmap.org", [20, 80], True)
|
||||
```
|
||||
|
||||
它应该返回以下内容:
|
||||
|
||||
```bash
|
||||
Open ports for scanme.nmap.org (45.33.32.156)
|
||||
PORT SERVICE
|
||||
22 ssh
|
||||
80 http
|
||||
```
|
||||
|
||||
确保包含正确的间距和换行符。
|
||||
|
||||
如果传入 `get_open_ports` 函数的 URL 无效,该函数应返回字符串:“Error: Invalid hostname”。
|
||||
|
||||
如果传入 `get_open_ports` 函数的 IP 地址无效,该函数应返回字符串:“Error: Invalid IP address”。
|
||||
|
||||
## 开发
|
||||
|
||||
在 `port_scanner.py` 中编写你的代码。 对于开发,你可以使用 `main.py` 来测试你的代码。 单击“运行”按钮,`main.py` 将运行。
|
||||
|
||||
## 测试
|
||||
|
||||
这个项目的单元测试在 `test_module.py` 中。 为了你的方便,我们将测试从 `test_module.py` 导入到 `main.py`。 只要你点击“运行”按钮,测试就会自动运行。
|
||||
|
||||
## 提交
|
||||
|
||||
复制项目的 URL 并将其提交给 freeCodeCamp。
|
||||
|
||||
# --hints--
|
||||
|
||||
|
@@ -9,22 +9,51 @@ dashedName: sha-1-password-cracker
|
||||
|
||||
# --description--
|
||||
|
||||
你将通过使用我们的 [Replit 入门代码](https://replit.com/github/freeCodeCamp/boilerplate-SHA-1-password-cracker) 来完成本项目。
|
||||
|
||||
我们仍在开发 Python 课程的交互式教学部分。 目前,你可以在 YouTube 上通过 freeCodeCamp.org 上传的一些视频学习这个项目相关的知识。
|
||||
|
||||
- [Python for Everybody 视频课程](https://www.freecodecamp.org/news/python-for-everybody/)(14 小时)
|
||||
|
||||
- [Learn Python 视频课程](https://www.freecodecamp.org/news/learn-python-video-course/)(10 小时)
|
||||
|
||||
# --instructions--
|
||||
|
||||
密码不应以纯文本形式存储。 它们应该存储为哈希值,以防万一密码列表被泄露。 然而,并不是所有的哈希都是一样的。
|
||||
|
||||
在这个项目中,你将通过创建一个密码破解器来找出使用 SHA-1 散列的密码,从而了解到良好安全的重要性。
|
||||
|
||||
你可以访问 [Replit 上的完整项目描述和启动代码](https://replit.com/github/freeCodeCamp/boilerplate-SHA-1-password-cracker)。
|
||||
创建一个函数,该函数接受密码的 SHA-1 哈希值,如果它是使用的前 10,000 个密码之一,则返回该密码。 如果 SHA-1 哈希不是数据库中的密码,则返回“密码不在数据库中”。
|
||||
|
||||
进入该链接后,fork 该项目。 一旦你根据 “README.md” 中的说明完成了项目,请在下面提交你的项目链接。
|
||||
该函数应该对 `top-10000-passwords.txt` 中的每个密码进行散列,并将其与传递给函数的散列进行比较。
|
||||
|
||||
我们仍在开发 Python 课程的交互式教学部分。 目前,freeCodeCamp.org YouTube 频道上的一些视频可以教你这个项目所需的一些 Python 技能。
|
||||
该函数应采用名为 `use_salts` 的可选第二个参数。 如果设置为 true,则文件 `known-salts.txt` 中的每个 salt 字符串,都应该在散列之前,和将它与传递给函数的哈希值进行比较之前,添加到 `top-10000-passwords.txt` 中的每个密码的之前和之后。
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href='https://www.freecodecamp.org/news/python-for-everybody/'>Python for Everybody 视频课程</a>(14 小时)
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://www.freecodecamp.org/news/learn-python-basics-in-depth-video-course/'>Learn Python 视频课程</a>(2 小时)
|
||||
</li>
|
||||
</ul>
|
||||
以下是一些用于测试该功能的散列密码:
|
||||
|
||||
- `b305921a3723cd5d70a375cd21a61e60aabb84ec` 应该返回 “sammy123”
|
||||
- `c7ab388a5ebefbf4d550652f1eb4d833e5316e3e` 应该返回 “abacab”
|
||||
- `5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8` 应该返回 “password”
|
||||
|
||||
以下是一些散列密码,用于在 `use_salts` 设置为 `True` 时测试该功能:
|
||||
|
||||
- `53d8b3dc9d39f0184144674e310185e41a87ffd5` 应该返回 “superman”
|
||||
- `da5a4e8cf89539e66097acd2f8af128acae2f8ae` 应该返回 “q1w2e3r4t5”
|
||||
- `ea3f62d498e3b98557f9f9cd0d905028b3b019e1` 应该返回 “bubbles1”
|
||||
|
||||
`hashlib` 库已经为你导入。 你应该在你的代码中使用它。 [在此了解更多关于 “hashlib” 的信息](https://docs.python.org/3/library/hashlib.html)
|
||||
|
||||
## 开发
|
||||
|
||||
在 `password_cracker.py` 中编写你的代码。 对于开发,你可以使用 `main.py` 来测试你的代码。 单击“运行”按钮,`main.py` 将运行。
|
||||
|
||||
## 测试
|
||||
|
||||
此项目的单元测试在 `test_module.py` 中。 为了你的方便,我们将测试从 `test_module.py` 导入到 `main.py`。 只要你点击“运行”按钮,测试就会自动运行。
|
||||
|
||||
## 提交
|
||||
|
||||
复制项目的 URL 并将其提交给 freeCodeCamp。
|
||||
|
||||
# --hints--
|
||||
|
||||
|
Reference in New Issue
Block a user