Skip to content

Commit 0a7f37b

Browse files
authored
Fix slider inputs (#1103)
* fix slider value propagation * use cached sub for sticky detect * user banning
1 parent 8f7ed11 commit 0a7f37b

21 files changed

+444
-187
lines changed

common/template-parser.ts

+17
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ export type TemplateOpts = {
3939
flags: { [key in Section]?: boolean }
4040
sections: { [key in Section]: string[] }
4141
done: boolean
42+
warnings: {
43+
noHistory: boolean
44+
noPost: boolean
45+
}
4246
}
4347

4448
/**
@@ -186,6 +190,10 @@ export async function parseTemplate(
186190
flags: {},
187191
sections: { system: [], history: [], post: [] },
188192
done: false,
193+
warnings: {
194+
noHistory: true,
195+
noPost: true,
196+
},
189197
}
190198

191199
opts.sections = sections
@@ -643,6 +651,7 @@ function renderIterator(holder: IterableHolder, children: CNode[], opts: Templat
643651
opts.limit.output[id] = { src: holder, lines: output }
644652
if (opts.sections) {
645653
opts.sections.flags.history = true
654+
opts.sections.warnings.noHistory = false
646655
}
647656
return id
648657
}
@@ -713,10 +722,18 @@ function getPlaceholder(
713722
return opts.jsonValues?.[node.values] || ''
714723

715724
case 'post': {
725+
if (opts.sections) {
726+
opts.sections.warnings.noPost = false
727+
}
728+
716729
return opts.parts?.post?.join('\n') || ''
717730
}
718731

719732
case 'history': {
733+
if (opts.sections) {
734+
opts.sections.warnings.noHistory = false
735+
}
736+
720737
if (opts.limit) {
721738
const id = `__${v4()}__`
722739
opts.limit.output![id] = {

common/types/schema.ts

+7
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,13 @@ export namespace AppSchema {
209209
lastChecked?: string
210210
}
211211
stripeSessions?: string[]
212+
213+
banned?: {
214+
at: Date
215+
reason: string
216+
}
217+
218+
banHistory?: Array<{ at: Date; reason: string }>
212219
}
213220

214221
export interface ApiKey {

srv/adapter/generate.ts

+15
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,21 @@ export async function createChatStream(
395395
*/
396396

397397
const prompt = await assemblePrompt(opts, opts.parts, opts.lines, encoder)
398+
399+
if (prompt.sections.warnings.noHistory) {
400+
throw new StatusError(
401+
`Your prompt template does not contain the 'chat history' placeholder. Please fix your prompt template.`,
402+
400
403+
)
404+
}
405+
406+
// if (prompt.sections.warnings.noPost) {
407+
// throw new StatusError(
408+
// `Your prompt template does not contain the 'post' placeholder. Please fix your prompt template.`,
409+
// 400
410+
// )
411+
// }
412+
398413
if (prompt.linesAddedCount === 0 && opts.linesCount) {
399414
throw new StatusError(
400415
`Could not fit any messages in prompt. Check your character definition, context size, and template`,

srv/api/admin.ts

+19
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,23 @@ const searchUsers = handle(async (req) => {
2626
return { users: users.map((u) => ({ ...u, hash: undefined })) }
2727
})
2828

29+
const banUser = handle(async (req) => {
30+
const user = await store.users.getUser(req.params.userId)
31+
assertValid({ reason: 'string' }, req.body)
32+
33+
if (!user) {
34+
throw new StatusError('User not found', 404)
35+
}
36+
37+
const next = await store.admin.banUser(req.params.userId, req.body.reason)
38+
return next
39+
})
40+
41+
const unbanUser = handle(async (req) => {
42+
const next = await store.admin.unbanUser(req.params.userId)
43+
return next
44+
})
45+
2946
const impersonateUser = handle(async (req) => {
3047
const userId = req.params.userId
3148
const user = await store.users.getUser(userId)
@@ -138,5 +155,7 @@ router.get('/users/:id/info', getUserInfo)
138155
router.post('/user/password', setUserPassword)
139156
router.post('/notify', notifyAll)
140157
router.post('/configuration', updateConfiguration)
158+
router.post('/ban/:userId', banUser)
159+
router.post('/unban/:userId', unbanUser)
141160

142161
export default router

srv/api/chat/message.ts

+1
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ export const generateMessageV2 = handle(async (req, res) => {
278278
).catch((err) => ({ err }))
279279

280280
if ('err' in chatStream) {
281+
await releaseLock(chatId)
281282
throw chatStream.err
282283
}
283284

srv/api/wrap.ts

+9
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ export class StatusError extends Error {
3131
}
3232
}
3333

34+
class BannedError extends StatusError {
35+
public banned = true
36+
37+
constructor(public reason: string) {
38+
super(reason, 401)
39+
}
40+
}
41+
3442
export type Handler = (req: AppRequest, res: express.Response, next: express.NextFunction) => any
3543

3644
export type AppRequest = Omit<express.Request, 'log'> & {
@@ -49,4 +57,5 @@ export const errors = {
4957
Unauthorized: new StatusError('Unauthorized', 401),
5058
Forbidden: new StatusError('Forbidden', 403),
5159
BadRequest: new StatusError('Bad request', 400),
60+
UserBanned: (reason: string) => new BannedError(reason || 'No reason given'),
5261
}

srv/api/ws/handlers.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type Handlers = {
2020
}
2121

2222
export const handlers: Handlers = {
23-
login: (client: AppSocket, data: any) => {
23+
login: async (client: AppSocket, data: any) => {
2424
assertValid({ token: 'string' }, data)
2525
try {
2626
if (client.userId) {
@@ -31,6 +31,12 @@ export const handlers: Handlers = {
3131
client.token = data.token
3232
client.userId = payload.userId
3333

34+
const user = await store.users.getUser(payload.userId)
35+
if (!user || user.banned) {
36+
client.dispatch({ type: 'login', success: false })
37+
return
38+
}
39+
3440
const sockets = userSockets.get(client.userId) || []
3541
sockets.push(client)
3642
userSockets.set(client.userId, sockets)

srv/app.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ export function createApp() {
2323
const app = express()
2424
const server = createServer(app)
2525

26-
app.use(express.urlencoded({ limit: `${config.limits.upload}mb`, extended: false }))
27-
app.use(express.json({ limit: `${config.limits.payload}mb` }))
28-
app.use(logMiddleware())
2926
app.use(
3027
cors({
3128
origin: true,
3229
optionsSuccessStatus: 200,
3330
})
3431
)
32+
app.use(express.urlencoded({ limit: `${config.limits.upload}mb`, extended: false }))
33+
app.use(express.json({ limit: `${config.limits.payload}mb` }))
34+
app.use(logMiddleware())
3535
app.use(upload.any())
3636

3737
const baseFolder = resolve(__dirname, '..')
@@ -94,6 +94,11 @@ export function createApp() {
9494
return res.sendFile(index)
9595
})
9696
app.use((err: any, _req: any, res: express.Response, _next: any) => {
97+
if (err.banned) {
98+
res.status(401)
99+
res.json({ message: err.message, user_banned: true })
100+
return
101+
}
97102
if (err.status > 0) {
98103
res.status(err.status)
99104
} else {

srv/db/admin.ts

+37
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { encryptPassword } from './util'
44
import { AppSchema } from '../../common/types/schema'
55
import { domain } from '../domains'
66
import { config } from '../config'
7+
import { StatusError } from '../api/wrap'
78

89
type UsersOpts = {
910
username?: string
@@ -104,6 +105,7 @@ export async function getUserInfo(userId: string) {
104105
patreon: 1,
105106
stripeSessions: 1,
106107
google: 1,
108+
banned: 1,
107109
},
108110
}
109111
)
@@ -122,3 +124,38 @@ export async function getUserInfo(userId: string) {
122124
...billing,
123125
}
124126
}
127+
128+
export async function banUser(userId: string, reason: string) {
129+
await db('user').updateOne(
130+
{ _id: userId },
131+
{
132+
$set: {
133+
banned: {
134+
at: new Date(),
135+
reason: reason || 'No reason given',
136+
},
137+
},
138+
}
139+
)
140+
141+
const next = await getUserInfo(userId)
142+
return next
143+
}
144+
145+
export async function unbanUser(userId: string) {
146+
const user = await db('user').findOne({ _id: userId })
147+
if (!user) {
148+
throw new StatusError(`User not found`, 404)
149+
}
150+
151+
if (!user.banned) {
152+
throw new StatusError(`User not banned`, 400)
153+
}
154+
155+
const banHistory = user.banHistory || []
156+
banHistory.push(user.banned)
157+
158+
await db('user').updateOne({ _id: userId }, { $set: { banHistory, banned: null as any } })
159+
const next = await getUserInfo(userId)
160+
return next
161+
}

srv/db/user.ts

+4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ export async function authenticate(username: string, password: string) {
7878
const user = await db('user').findOne({ username: username.toLowerCase() })
7979
if (!user) return
8080

81+
if (user.banned) {
82+
throw errors.UserBanned(user.banned.reason)
83+
}
84+
8185
const match = await bcrypt.compare(password, user.hash)
8286
if (!match) return
8387

srv/middleware.ts

+6
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ export function logMiddleware() {
134134
return next(errors.Unauthorized)
135135
}
136136

137+
if (user.banned) {
138+
// res.status(401)
139+
res.json({ message: `${user.banned.reason}`, user_banned: true })
140+
return
141+
}
142+
137143
const sub = getUserSubscriptionTier(user, getCachedTiers())
138144
req.authed = user
139145
req.tier = sub?.tier

tests/__snapshots__/placeholder.spec.js.snap

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ MainChar's personality: MainCharacter talks a lot",
2222
"MainChar's personality: MainCharacter talks a lot",
2323
],
2424
},
25+
"warnings": Object {
26+
"noHistory": true,
27+
"noPost": true,
28+
},
2529
},
2630
}
2731
`;

web/App.tsx

+21
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ const Layout: Component<{ children?: any }> = (props) => {
179179
<Maintenance />
180180
</Match>
181181

182+
<Match when={!!state.banned}>
183+
<div class="flex h-[80vh] flex-col items-center justify-center gap-2"></div>
184+
</Match>
185+
182186
<Match when={cfg.initLoading}>
183187
<div class="flex h-[80vh] flex-col items-center justify-center gap-2">
184188
<div>
@@ -211,6 +215,7 @@ const Layout: Component<{ children?: any }> = (props) => {
211215
/>
212216
<InfoModal />
213217
<ProfileModal />
218+
<BannedModal />
214219
<For each={rootModals.modals}>{(modal) => modal.element}</For>
215220
<ImageModal />
216221
<Show when={cfg.showImgSettings}>
@@ -243,4 +248,20 @@ const InfoModal: Component = (props) => {
243248
)
244249
}
245250

251+
const BannedModal: Component = () => {
252+
const state = userStore((u) => ({
253+
banned: u.banned,
254+
}))
255+
256+
return (
257+
<Modal show={!!state.banned} close={() => userStore.logout()} title="Account Banned">
258+
<div class="flex flex-col items-center">
259+
<p class="">This account has been banned for the following reason:</p>
260+
<p class="my-2 flex items-center font-bold">{state.banned}</p>
261+
<p>If you believe this is an error, please contact support.</p>
262+
</div>
263+
</Modal>
264+
)
265+
}
266+
246267
export default App

web/emitter.ts

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const EVENTS = {
1919
checkoutSuccess: 'checkout-success',
2020
chatOpened: 'chat-opened',
2121
chatClosed: 'chat-closed',
22+
userBanned: 'user-banned',
2223
} as const
2324

2425
type EventType = (typeof EVENTS)[keyof typeof EVENTS]

0 commit comments

Comments
 (0)