Initial commit: Memind H5 portal with MindSpace, Plaza, and agent jobs.
Track application source and tests; exclude local env, user workspaces, and runtime data via .gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { publicationInternals } from './mindspace-publications.mjs';
|
||||
|
||||
test('normalizes safe long-page slugs', () => {
|
||||
assert.equal(publicationInternals.normalizeSlug(' product-intro-2026 '), 'product-intro-2026');
|
||||
assert.throws(
|
||||
() => publicationInternals.normalizeSlug('../private'),
|
||||
(error) => error.code === 'invalid_publish_input',
|
||||
);
|
||||
assert.throws(
|
||||
() => publicationInternals.normalizeSlug('中文地址'),
|
||||
(error) => error.code === 'invalid_publish_input',
|
||||
);
|
||||
});
|
||||
|
||||
test('accepts all documented access modes', () => {
|
||||
for (const mode of [
|
||||
'public',
|
||||
'password',
|
||||
'private_link',
|
||||
'time_limited',
|
||||
'login_required',
|
||||
'owner_only',
|
||||
]) {
|
||||
assert.equal(publicationInternals.normalizeAccessMode(mode), mode);
|
||||
}
|
||||
assert.throws(
|
||||
() => publicationInternals.normalizeAccessMode('team_only'),
|
||||
(error) => error.code === 'invalid_publish_input',
|
||||
);
|
||||
});
|
||||
|
||||
test('hashes access passwords with a random salt', () => {
|
||||
const first = publicationInternals.hashPassword('Publish-Password-2026');
|
||||
const second = publicationInternals.hashPassword('Publish-Password-2026');
|
||||
assert.notEqual(first, second);
|
||||
assert.equal(publicationInternals.verifyPassword('Publish-Password-2026', first), true);
|
||||
assert.equal(publicationInternals.verifyPassword('wrong-password', first), false);
|
||||
assert.throws(
|
||||
() => publicationInternals.normalizePassword('short', true),
|
||||
(error) => error.code === 'invalid_publish_input',
|
||||
);
|
||||
});
|
||||
|
||||
test('requires future expiry timestamps for time-limited pages', () => {
|
||||
const future = Date.now() + 60_000;
|
||||
assert.equal(publicationInternals.normalizeExpiresAt(future, true), future);
|
||||
assert.throws(
|
||||
() => publicationInternals.normalizeExpiresAt(Date.now() - 1, true),
|
||||
(error) => error.code === 'invalid_publish_input',
|
||||
);
|
||||
});
|
||||
|
||||
test('classifies devices and strips referrer paths', () => {
|
||||
assert.equal(
|
||||
publicationInternals.deviceType('Mozilla/5.0 (iPhone; CPU iPhone OS 18_0) Mobile'),
|
||||
'mobile',
|
||||
);
|
||||
assert.equal(publicationInternals.deviceType('Googlebot/2.1'), 'bot');
|
||||
assert.equal(publicationInternals.deviceType('Mozilla/5.0 (Macintosh)'), 'desktop');
|
||||
assert.equal(
|
||||
publicationInternals.referrerHost('https://example.com/private/path?token=secret'),
|
||||
'example.com',
|
||||
);
|
||||
assert.equal(publicationInternals.referrerHost('not a url'), null);
|
||||
});
|
||||
|
||||
test('warns for contact details and external links without silently hiding them', () => {
|
||||
const result = publicationInternals.scanContent(
|
||||
'联系 13812345678 或 hello@example.com,详情 https://example.com/path',
|
||||
);
|
||||
assert.equal(result.status, 'warned');
|
||||
assert.equal(result.riskLevel, 'medium');
|
||||
assert.equal(result.allowed, true);
|
||||
assert.deepEqual(
|
||||
result.findings.map((finding) => finding.type),
|
||||
['phone', 'email', 'external_link'],
|
||||
);
|
||||
assert.doesNotMatch(result.findings[0].sampleMasked, /13812345678/);
|
||||
});
|
||||
|
||||
test('deduplicates the same sensitive value repeated by summary and content', () => {
|
||||
const result = publicationInternals.scanContent(
|
||||
'摘要 qa@example.com\n正文 qa@example.com',
|
||||
);
|
||||
assert.equal(result.findings[0].occurrenceCount, 1);
|
||||
});
|
||||
|
||||
test('blocks identity and bank-card numbers', () => {
|
||||
const result = publicationInternals.scanContent(
|
||||
'身份证 310101199001011234,银行卡 6222021234567890123',
|
||||
);
|
||||
assert.equal(result.status, 'blocked');
|
||||
assert.equal(result.riskLevel, 'high');
|
||||
assert.equal(result.allowed, false);
|
||||
assert.ok(result.findings.every((finding) => finding.blocking));
|
||||
});
|
||||
|
||||
test('publicHomepageResponse summarizes public cards and total views', () => {
|
||||
const result = publicationInternals.publicHomepageResponse(
|
||||
{
|
||||
id: 'user-1',
|
||||
slug: 'john',
|
||||
username: 'john',
|
||||
display_name: 'John',
|
||||
},
|
||||
[
|
||||
{
|
||||
id: 'pub-1',
|
||||
page_id: 'page-1',
|
||||
title: '第一篇',
|
||||
summary: '摘要一',
|
||||
template_id: 'report',
|
||||
public_url: '/u/john/pages/one',
|
||||
url_slug: 'one',
|
||||
view_count: 7,
|
||||
published_at: 100,
|
||||
},
|
||||
{
|
||||
id: 'pub-2',
|
||||
page_id: 'page-2',
|
||||
title: '第二篇',
|
||||
summary: '摘要二',
|
||||
template_id: 'editorial',
|
||||
public_url: '/u/john/pages/two',
|
||||
url_slug: 'two',
|
||||
view_count: 3,
|
||||
published_at: 200,
|
||||
},
|
||||
],
|
||||
);
|
||||
assert.equal(result.owner.displayName, 'John');
|
||||
assert.equal(result.totalViews, 10);
|
||||
assert.equal(result.pageCount, 2);
|
||||
assert.equal(result.pages[0].publicUrl, '/u/john/pages/one');
|
||||
});
|
||||
Reference in New Issue
Block a user