Skip to content

Commit 7004ea1

Browse files
committed
Updating index files and sending emails to users with invalid usernames
1 parent fd6b00b commit 7004ea1

File tree

3 files changed

+144
-34
lines changed

3 files changed

+144
-34
lines changed

bin/lib/blacklist.js

Lines changed: 91 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
const fs = require('fs')
2-
const util = require('util')
2+
const Handlebars = require('handlebars')
3+
const path = require('path')
34
const { URL } = require('url')
5+
const util = require('util')
46

57
const { loadConfig } = require('./common')
68
const { isValidUsername } = require('../../lib/common/user-utils')
79
const blacklistService = require('../../lib/services/blacklist-service')
10+
const { initConfigDir, initTemplateDirs } = require('../../lib/server-config')
811

9-
// const AccountManager = require('../../lib/models/account-manager')
10-
// const LDP = require('../../lib/ldp')
11-
// const SolidHost = require('../../lib/models/solid-host')
12+
const AccountManager = require('../../lib/models/account-manager')
13+
const EmailService = require('../../lib/services/email-service')
14+
const LDP = require('../../lib/ldp')
15+
const SolidHost = require('../../lib/models/solid-host')
16+
17+
const fileExists = util.promisify(fs.exists)
18+
const fileRename = util.promisify(fs.rename)
1219

1320
module.exports = function (program) {
1421
program
@@ -22,29 +29,13 @@ module.exports = function (program) {
2229
return console.error('You are running a single user server, no need to check for blacklisted users')
2330
}
2431

25-
// const host = SolidHost.from({ port: config.port, serverUri: config.serverUri })
2632
const invalidUsernames = await getInvalidUsernames(config)
2733

28-
// const ldp = new LDP(config)
29-
// const accountManager = AccountManager.from({
30-
// // authMethod: argv.auth,
31-
// // emailService: app.locals.emailService,
32-
// // tokenService: app.locals.tokenService,
33-
// host,
34-
// // accountTemplatePath: argv.templates.account,
35-
// store: ldp,
36-
// multiuser: config.multiuser
37-
// })
38-
// const blacklistedUsernames = await getBlacklistedUsernames(accountManager)
39-
// if (blacklistedUsernames.length === 0) {
40-
// console.log('No blacklisted username was found')
41-
// }
42-
// console.log(`These blacklisted usernames were found:${blacklistedUsernames.map(username => `\n- ${username}`)}`)
43-
44-
if (invalidUsernames.length === 0) {
45-
console.log('No invalid username was found')
34+
if (options.notify) {
35+
return notifyUsers(invalidUsernames, config)
4636
}
47-
console.log(`${invalidUsernames.length} invalid usernames were found:${invalidUsernames.map(username => `\n- ${username}`)}`)
37+
38+
listUsernames(listUsernames)
4839
})
4940
}
5041

@@ -58,13 +49,79 @@ async function getInvalidUsernames (config) {
5849
.filter(username => !isValidUsername(username) || !blacklistService.validate(username))
5950
}
6051

61-
// async function getBlacklistedUsernames (accountManager) {
62-
// const blacklistedUsernames = []
63-
// await Promise.all(blacklistService.list.map(async (word) => {
64-
// const accountExists = await accountManager.accountExists(word)
65-
// if (accountExists) {
66-
// blacklistedUsernames.push(word)
67-
// }
68-
// }))
69-
// return blacklistedUsernames
70-
// }
52+
function listUsernames (usernames) {
53+
if (usernames.length === 0) {
54+
console.info('No invalid usernames was found')
55+
}
56+
console.info(`${usernames.length} invalid usernames were found:${usernames.map(username => `\n- ${username}`)}`)
57+
}
58+
59+
async function notifyUsers (usernames, config) {
60+
const ldp = new LDP(config)
61+
const host = SolidHost.from({ port: config.port, serverUri: config.serverUri })
62+
const accountManager = AccountManager.from({
63+
host,
64+
store: ldp,
65+
multiuser: config.multiuser
66+
})
67+
const twoWeeksFromNow = Date.now() + 14 * 24 * 60 * 60 * 1000
68+
const dateOfRemoval = (new Date(twoWeeksFromNow)).toLocaleDateString()
69+
const supportEmail = '[email protected]'
70+
71+
await updateIndexFiles(usernames, accountManager, dateOfRemoval, supportEmail)
72+
await sendEmails(config, usernames, accountManager, dateOfRemoval, supportEmail)
73+
}
74+
75+
async function updateIndexFiles (usernames, accountManager, dateOfRemoval, supportEmail) {
76+
const invalidUsernameFilePath = path.join(process.cwd(), 'default-views/account/invalid-username.hbs')
77+
const fileOptions = {
78+
encoding: 'utf-8'
79+
}
80+
const source = fs.readFileSync(invalidUsernameFilePath, fileOptions)
81+
const invalidUsernameTemplate = Handlebars.compile(source)
82+
const updatingFiles = usernames.map(username => createNewIndex(username, accountManager, invalidUsernameTemplate, dateOfRemoval, supportEmail, fileOptions))
83+
return Promise.all(updatingFiles)
84+
}
85+
86+
async function createNewIndex (username, accountManager, invalidUsernameTemplate, dateOfRemoval, supportEmail, fileOptions) {
87+
const userDirectory = accountManager.accountDirFor(username)
88+
const currentIndex = path.join(userDirectory, 'index.html')
89+
const currentIndexExists = await fileExists(currentIndex)
90+
const backupIndex = path.join(userDirectory, 'index.backup.html')
91+
const backupIndexExists = await fileExists(backupIndex)
92+
if (currentIndexExists && !backupIndexExists) {
93+
await fileRename(currentIndex, backupIndex)
94+
const newIndexSource = invalidUsernameTemplate({
95+
username,
96+
dateOfRemoval,
97+
supportEmail
98+
})
99+
fs.writeFileSync(currentIndex, newIndexSource, fileOptions)
100+
console.info(`index.html updated for user ${username}`)
101+
}
102+
}
103+
104+
async function sendEmails (config, usernames, accountManager, dateOfRemoval, supportEmail) {
105+
if (config.email && config.email.host) {
106+
const configPath = initConfigDir(config)
107+
const templates = initTemplateDirs(configPath)
108+
const users = await Promise.all(await usernames.map(async username => {
109+
const emailAddress = await accountManager.loadAccountRecoveryEmail({ username })
110+
const accountUri = accountManager.accountUriFor(username)
111+
return { username, emailAddress, accountUri }
112+
}))
113+
const emailService = new EmailService(templates.email, config.email)
114+
const sendingEmails = await users
115+
.filter(user => !!user.emailAddress)
116+
.map(async user => await emailService.sendWithTemplate('invalid-username', {
117+
to: user.emailAddress,
118+
accountUri: user.accountUri,
119+
dateOfRemoval,
120+
supportEmail
121+
}))
122+
const emailsSent = await Promise.all(sendingEmails)
123+
console.info(`${emailsSent.length} emails sent to users with invalid usernames`)
124+
}
125+
console.info('You have not configured an email service.')
126+
console.info('Please set it up to send users email about their accounts')
127+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module.exports.render = render
2+
3+
function render (data) {
4+
return {
5+
subject: `Invalid username for account ${data.accountUri}`,
6+
7+
/**
8+
* Text version
9+
*/
10+
text: `Hi,
11+
12+
We're sorry to inform you that the username for account ${data.accountUri} is not allowed after changes to username policy.
13+
14+
This account has been set to be deleted at ${data.dateOfRemoval}.
15+
16+
${data.supportEmail ? `Please contact ${data.supportEmail} if you want to move your account.` : ''}`,
17+
18+
/**
19+
* HTML version
20+
*/
21+
html: `<p>Hi,</p>
22+
23+
<p>We're sorry to inform you that the username for account ${data.accountUri} is not allowed after changes to username policy.</p>
24+
25+
<p>This account has been set to be deleted at ${data.dateOfRemoval}.</p>
26+
27+
${data.supportEmail ? `<p>Please contact ${data.supportEmail} if you want to move your account.</p>` : ''}
28+
`
29+
}
30+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
<title>Invalid username</title>
7+
<link rel="stylesheet" href="/common/css/bootstrap.min.css">
8+
<script></script>
9+
</head>
10+
<body>
11+
<div class="container">
12+
<h4>Invalid username</h4>
13+
</div>
14+
<div class="container">
15+
<p>We're sorry to inform you that this account's username ({{username}}) is not allowed after changes to username policy.</p>
16+
<p>This account has been set to be deleted at {{dateOfRemoval}}.</p>
17+
{{#if supportEmail}}
18+
<p>Please contact {{supportEmail}} if you want to move your account.</p>
19+
{{/if}}
20+
<p>If you had an email address connected to this account, you should have received an email about this.</p>
21+
</div>
22+
</body>
23+
</html>

0 commit comments

Comments
 (0)