Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions codegen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ overwrite: true
schema:
'src/schema/**/*.ts':
noRequire: true
hooks:
afterAllFileWrite:
- prettier --write
generates:
src/types/generated/schema-types.ts:
plugins:
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"knex": "^3.2.10",
"knex-postgis": "^0.14.3",
"lodash": "^4.17.11",
"lusca": "^1.7.0",
"moment": "^2.24.0",
"moment-timezone": "^0.5.23",
"node-fetch": "^2.3.0",
Expand All @@ -95,6 +96,7 @@
"@types/ioredis": "^4.0.9",
"@types/jest": "^30",
"@types/lodash": "^4.14.122",
"@types/lusca": "^1.7.5",
"@types/node": "^20",
"@types/validator": "^13.15.4",
"concurrently": "^4.1.0",
Expand Down
14 changes: 13 additions & 1 deletion src/admin/adminController.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import express from 'express'
import lusca from 'lusca'
import {
DomainGroup,
getSettings,
Expand All @@ -19,9 +20,20 @@ export const adminController = async (adminPath) => {
const prefixedAdminPath = join(PATH_PREFIX, adminPath)
const adminRouter = express.Router()

// Protect the state-changing admin form submissions (rendered as HTML forms
// and posted as application/x-www-form-urlencoded) against CSRF. lusca.csrf
// stores a secret in the existing session and exposes the per-session token
// as `res.locals._csrf`, which must be echoed back via the hidden `_csrf`
// field embedded in each form.
adminRouter.use(lusca.csrf())

adminRouter.get('/', async (req, res) => {
const currentState = await getSettings()
res.render('Admin', { adminPath: prefixedAdminPath, settings: currentState })
res.render('Admin', {
adminPath: prefixedAdminPath,
settings: currentState,
csrfToken: res.locals._csrf,
})
})

function createDomainGroupsFromInput(input: string): DomainGroup[] {
Expand Down
8 changes: 5 additions & 3 deletions src/types/generated/resolver-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1117,8 +1117,8 @@ export type ResolversTypes = {
Mutation: ResolverTypeWrapper<{}>
Feedback: ResolverTypeWrapper<Feedback>
Upload: ResolverTypeWrapper<Scalars['Upload']>
BBox: ResolverTypeWrapper<Scalars['BBox']>
TlpType: TlpType
BBox: ResolverTypeWrapper<Scalars['BBox']>
}

/** Mapping between all available schema types and the resolvers parents */
Expand Down Expand Up @@ -1165,7 +1165,9 @@ export type ResolversParentTypes = {
ObservedArrival: ObservedArrival
ObservedDeparture: ObservedDeparture
ExceptionDay: ExceptionDay
Journey: Omit<Journey, 'events'> & { events: ResolversParentTypes['JourneyEventType'][] }
Journey: Omit<Journey, 'events'> & {
events: ResolversParentTypes['JourneyEventType'][]
}
VehiclePosition: VehiclePosition
JourneyEventType:
| ResolversParentTypes['JourneyEvent']
Expand Down Expand Up @@ -1193,8 +1195,8 @@ export type ResolversParentTypes = {
Mutation: {}
Feedback: Feedback
Upload: Scalars['Upload']
BBox: Scalars['BBox']
TlpType: TlpType
BBox: Scalars['BBox']
}

export type AlertResolvers<
Expand Down
9 changes: 5 additions & 4 deletions src/views/Admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import GroupAssignment from './components/GroupAssignment'
import AutoDomainGroups from './components/AutoDomainGroups'
import join from 'proper-url-join'

const AdminView = ({ adminPath, settings }) => {
const AdminView = ({ adminPath, settings, csrfToken }) => {
return (
<>
<h1>Transitlog server admin</h1>
<hr />
<UIMessageForm adminPath={adminPath} settings={settings} />
<GroupAssignment adminPath={adminPath} settings={settings} />
<AutoDomainGroups adminPath={adminPath} settings={settings} />
<UIMessageForm adminPath={adminPath} settings={settings} csrfToken={csrfToken} />
<GroupAssignment adminPath={adminPath} settings={settings} csrfToken={csrfToken} />
<AutoDomainGroups adminPath={adminPath} settings={settings} csrfToken={csrfToken} />
<hr />
<h3>Clear cache</h3>
<p>
If the cache contains old data you may clear the whole cache here. Remember that this
will result in some queries taking longer due to being fetched from the DB.
</p>
<form method="post" action={join(adminPath, 'clear-cache')}>
<input type="hidden" name="_csrf" value={csrfToken} />
<input type="submit" value="Clear cache" />
</form>
</>
Expand Down
3 changes: 2 additions & 1 deletion src/views/components/AutoDomainGroups.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React from 'react'
import join from 'proper-url-join'
import { get } from 'lodash'

const AutoDomainGroups = ({ adminPath, settings }) => {
const AutoDomainGroups = ({ adminPath, settings, csrfToken }) => {
const assignedGroups = get(settings, 'auto_domain_groups', [])

return (
<>
<h3>Create groups for emails</h3>
<form action={join(adminPath, 'set-auto-groups')} method="post">
<input type="hidden" name="_csrf" value={csrfToken} />
<fieldset>
<legend>HSL ID group creation</legend>
<p>
Expand Down
3 changes: 2 additions & 1 deletion src/views/components/GroupAssignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React from 'react'
import join from 'proper-url-join'
import { get } from 'lodash'

const GroupAssignment = ({ adminPath, settings }) => {
const GroupAssignment = ({ adminPath, settings, csrfToken }) => {
const assignedGroups = get(settings, 'domain_groups', [])

return (
<>
<h3>Assign email domains to groups</h3>
<form action={join(adminPath, 'set-groups')} method="post">
<input type="hidden" name="_csrf" value={csrfToken} />
<fieldset>
<legend>HSL ID group assignment</legend>
<p>
Expand Down
3 changes: 2 additions & 1 deletion src/views/components/UIMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import React from 'react'
import join from 'proper-url-join'
import { get } from 'lodash'

const UIMessageForm = ({ settings, adminPath }) => {
const UIMessageForm = ({ settings, adminPath, csrfToken }) => {
const message = get(settings, 'ui_message') || { date: '', message: '' }

return (
<>
<h3>Set UI message</h3>
<form method="post" action={join(adminPath, 'set-ui-message')}>
<input type="hidden" name="_csrf" value={csrfToken} />
<fieldset>
<legend>UI message</legend>
<p>Set a message that is shown in the UI.</p>
Expand Down
37 changes: 34 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2608,9 +2608,21 @@
integrity sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==

"@types/long@^4.0.0":
version "4.0.2"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.2.tgz#b74129719fc8d11c01868010082d483b7545591a"
integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==
version "4.0.1"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==

"@types/lusca@^1.7.5":
version "1.7.5"
resolved "https://registry.yarnpkg.com/@types/lusca/-/lusca-1.7.5.tgz#6fff257dc11176bd3150afba90790e626a12cd0f"
integrity sha512-l49gAf8pu2iMzbKejLcz6Pqj+51H2na6BgORv1ElnE8ByPFcBdh/eZ0WNR1Va/6ZuNSZa01Hoy1DTZ3IZ+y+kA==
dependencies:
"@types/express" "*"

"@types/mime@^1":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==

"@types/minimatch@*":
version "6.0.0"
Expand Down Expand Up @@ -6947,6 +6959,20 @@ lru-cache@^5.0.0, lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"

lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"

lusca@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/lusca/-/lusca-1.7.0.tgz#a5d979f1b51776e60d41e0ca98f886f1b8b95502"
integrity sha512-msnrplCfY7zaqlZBDEloCIKld+RUeMZVeWzSPaGUKeRXFlruNSdKg2XxCyR+zj6BqzcXhXlRnvcvx6rAGgsvMA==
dependencies:
tsscmp "^1.0.5"

make-dir@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
Expand Down Expand Up @@ -9307,6 +9333,11 @@ tslint@^6.1.3:
tslib "^1.13.0"
tsutils "^2.29.0"

tsscmp@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"
integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==

tsutils@^2.29.0:
version "2.29.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
Expand Down
Loading