213 lines
5.5 KiB
JavaScript
213 lines
5.5 KiB
JavaScript
const Attachment = require('../../models/Attachment')
|
|
const User = require('../../models/User')
|
|
const ScrapeQueue = require('@workers/ScrapeQueue')
|
|
const Schema = require('@helpers/Schema')
|
|
const Robots = require('@helpers/Robots')
|
|
const FetchMock = require('../support/fetchMock')
|
|
const dns = require('dns').promises
|
|
|
|
let dnsSpy = null
|
|
|
|
const testUserName = 'jestTestUserAttachment'
|
|
const password = 'Beans19934!!!'
|
|
|
|
let newUserId = null
|
|
let masterKey = null
|
|
let newPushKey = null
|
|
|
|
beforeAll(() => {
|
|
|
|
// Find and Delete Previous Test user, log in, get key
|
|
return User.getByUserName(testUserName)
|
|
.then((user) => {
|
|
return User.deleteUser(user?.id, password)
|
|
})
|
|
.then((results) => {
|
|
|
|
return User.register(testUserName, password)
|
|
})
|
|
.then(({ token, userId }) => {
|
|
newUserId = userId
|
|
|
|
return User.getMasterKey(userId, password)
|
|
})
|
|
.then((newMasterKey) => {
|
|
masterKey = newMasterKey
|
|
|
|
return true
|
|
})
|
|
.catch(((error) => {
|
|
console.log(error)
|
|
}))
|
|
|
|
})
|
|
|
|
|
|
test('Test Generate Push Key', () => {
|
|
|
|
return Attachment.generatePushKey(newUserId)
|
|
.then( (pushKey) => {
|
|
newPushKey = pushKey
|
|
return Attachment.generatePushKey(newUserId)
|
|
})
|
|
.then( (pushKey) => {
|
|
// expect a long, defined pushkey
|
|
expect(pushKey).toBeDefined()
|
|
expect(pushKey?.length).toBeGreaterThan(20)
|
|
expect(pushKey).toMatch(newPushKey)
|
|
})
|
|
})
|
|
|
|
|
|
|
|
test('Test get Push Key Bookmarklet', () => {
|
|
|
|
return Attachment.getPushkeyBookmarklet(newUserId)
|
|
.then(( bookmarklet => {
|
|
// Expect a bookmarklet containting URL encoded pushkey from above
|
|
const keyCheck = bookmarklet.includes(encodeURIComponent(newPushKey))
|
|
|
|
expect(bookmarklet).toBeDefined()
|
|
expect(keyCheck).toBe(true)
|
|
|
|
}))
|
|
})
|
|
|
|
|
|
//
|
|
// These used to hit https://www.solidscribe.com over the live network, so the
|
|
// suite needed internet access and the assertion depended on whatever that page
|
|
// happened to serve. fetch is mocked against a fixture instead.
|
|
//
|
|
describe('Push URL', () => {
|
|
|
|
beforeEach(() => {
|
|
FetchMock.install()
|
|
// The server marks this at boot; there is no boot phase in tests.
|
|
Schema.__setReady(true)
|
|
Robots.__resetCache()
|
|
dnsSpy = jest.spyOn(dns, 'lookup').mockResolvedValue([{ address: '93.184.216.34', family: 4 }])
|
|
// Real code path, no politeness waiting and no robots lookups.
|
|
ScrapeQueue.configure({ perHostMinSpacingMs: 0, perHostMaxSpacingMs: 0, checkRobots: false })
|
|
})
|
|
|
|
afterEach(() => {
|
|
FetchMock.restore()
|
|
dnsSpy.mockRestore()
|
|
ScrapeQueue.__reset()
|
|
Schema.__reset()
|
|
})
|
|
|
|
test('scrapes a pushed url into a searchable attachment', () => {
|
|
|
|
const url = 'https://www.solidscribe.com/'
|
|
|
|
FetchMock.route(url, () => FetchMock.html(`
|
|
<html><head>
|
|
<title>Solid Scribe</title>
|
|
<meta property="og:description" content="An encrypted note taking application.">
|
|
</head><body><p>x</p></body></html>
|
|
`))
|
|
|
|
return Attachment.pushUrl(newPushKey, url)
|
|
.then(() => ScrapeQueue.drain())
|
|
.then(() => Attachment.textSearch(newUserId, 'scribe'))
|
|
.then(results => {
|
|
expect(results.length == 1).toBe(true)
|
|
expect(results[0].text).toContain('Solid Scribe')
|
|
})
|
|
})
|
|
|
|
test('stores the description so it is searchable too', () => {
|
|
|
|
const url = 'https://www.solidscribe.com/encrypted'
|
|
|
|
FetchMock.route(url, () => FetchMock.html(`
|
|
<html><head>
|
|
<title>Encryption Page</title>
|
|
<meta property="og:description" content="Notes are sealed with aes256gcm.">
|
|
</head><body><p>x</p></body></html>
|
|
`))
|
|
|
|
return Attachment.pushUrl(newPushKey, url)
|
|
.then(() => ScrapeQueue.drain())
|
|
.then(() => Attachment.textSearch(newUserId, 'aes256gcm'))
|
|
.then(results => {
|
|
expect(results.length).toBeGreaterThan(0)
|
|
})
|
|
})
|
|
|
|
// The pushmebaby query param was previously passed through with no
|
|
// validation whatsoever.
|
|
test('refuses a pushed url pointing at loopback and makes no request', () => {
|
|
|
|
FetchMock.route(/.*/, () => FetchMock.html('<title>should never load</title>'))
|
|
|
|
return Attachment.pushUrl(newPushKey, 'http://127.0.0.1:3000/admin')
|
|
.then(result => {
|
|
expect(result).toBe(true)
|
|
expect(FetchMock.callCount()).toBe(0)
|
|
})
|
|
})
|
|
|
|
test('refuses a pushed url pointing at the cloud metadata endpoint', () => {
|
|
|
|
FetchMock.route(/.*/, () => FetchMock.html('<title>should never load</title>'))
|
|
|
|
return Attachment.pushUrl(newPushKey, 'http://169.254.169.254/latest/meta-data/')
|
|
.then(() => {
|
|
expect(FetchMock.callCount()).toBe(0)
|
|
})
|
|
})
|
|
|
|
test('resolves truthy for an unknown pushkey without scraping', () => {
|
|
|
|
FetchMock.route(/.*/, () => FetchMock.html('<title>nope</title>'))
|
|
|
|
return Attachment.pushUrl('not-a-real-pushkey', 'https://example.com/')
|
|
.then(result => {
|
|
expect(result).toBe(true)
|
|
expect(FetchMock.callCount()).toBe(0)
|
|
})
|
|
})
|
|
|
|
// Previously this could hang the HTTP response indefinitely.
|
|
test('returns within the budget when the server never responds', () => {
|
|
|
|
const url = 'https://www.solidscribe.com/slow'
|
|
FetchMock.route(url, () => FetchMock.hang())
|
|
|
|
ScrapeQueue.configure({
|
|
perHostMinSpacingMs: 0,
|
|
perHostMaxSpacingMs: 0,
|
|
checkRobots: false,
|
|
pageTimeoutMs: 80,
|
|
totalBudgetMs: 300,
|
|
retries: 0,
|
|
})
|
|
|
|
const startedAt = Date.now()
|
|
|
|
return Attachment.pushUrl(newPushKey, url)
|
|
.then(result => {
|
|
expect(result).toBe(true)
|
|
expect(Date.now() - startedAt).toBeLessThan(5000)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('Test Delete Push Key', () => {
|
|
|
|
return Attachment.deletePushKey(newUserId)
|
|
.then(( results => {
|
|
// Expect a true bool
|
|
expect(results).toBe(true)
|
|
}))
|
|
})
|
|
|
|
afterAll(done => {
|
|
// Close Database
|
|
const db = require('../../config/database')
|
|
db.end()
|
|
done()
|
|
}) |