Skip to content

Commit

Permalink
feat: add shield_config patcher
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien-R44 committed Oct 17, 2023
1 parent 16e7c4f commit a6aa6b7
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/commands/upgrade_config_files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { sessionConfig } from '../patchers/config_files/session_config.js'
import { bodyparserConfig } from '../patchers/config_files/bodyparser_config.js'
import { databaseConfig } from '../patchers/config_files/database_config.js'
import { hashConfig } from '../patchers/config_files/hash_config.js'
import { shieldConfig } from '../patchers/config_files/shield_config.js'

export class UpgradeConfigFiles extends BaseCommand {
static commandName = `upgrade-config-files`
Expand All @@ -24,6 +25,7 @@ export class UpgradeConfigFiles extends BaseCommand {
staticConfig(),
databaseConfig(),
hashConfig(),
shieldConfig(),
],
projectPath: this.projectPath,
}).run()
Expand Down
55 changes: 55 additions & 0 deletions src/patchers/config_files/shield_config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { SyntaxKind } from 'ts-morph'
import { PatcherFactory } from '../../types/index.js'
import { ConfigUpdaterPatcher } from '../config_updater_patcher.js'

export function shieldConfig(): PatcherFactory {
return (runner) => new ShieldConfig(runner)
}

/**
* Rewrite the config/shield.ts file to use the new API
*/
export class ShieldConfig extends ConfigUpdaterPatcher {
static patcherName = 'shield-config'

async invoke() {
super.invoke()

const file = this.getConfigFile('config/shield.ts')
if (!file) return

/**
* Take each configuration section exported from the old file
* and create a new object literal that will include all
*/
const exportedDeclarations = file.getExportedDeclarations()
const sections = ['csp', 'csrf', 'xframe', 'hsts', 'contentTypeSniffing', 'dnsPrefetchControl']

let configObjectLiteral = '{\n'

sections.forEach((sectionName) => {
const symbols = exportedDeclarations.get(sectionName)
if (!symbols) return

const symbol = symbols[0].getChildrenOfKind(SyntaxKind.ObjectLiteralExpression)
configObjectLiteral += sectionName + ': ' + symbol[0].getText() + ',\n'
})

configObjectLiteral += '}'

/**
* Write the new file
*/
const newContent = `
import { defineConfig } from '@adonisjs/shield'
export default defineConfig(${configObjectLiteral})
`
file.replaceWithText(newContent)
await this.formatFile(file).save()

this.logger.info('Updated config/shield.ts file')

this.exit()
}
}
88 changes: 88 additions & 0 deletions tests/shield_config.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import dedent from 'dedent'
import { test } from '@japa/runner'

import { createRunner } from '../test_helpers/index.js'
import { shieldConfig } from '../src/patchers/config_files/shield_config.js'

test.group('Shield config', () => {
test('Update shield config', async ({ assert, fs }) => {
await fs.setupProject({})

await fs.create(
'config/shield.ts',
dedent`
import Env from '@ioc:Adonis/Core/Env'
import { ShieldConfig } from '@ioc:Adonis/Addons/Shield'
export const csp: ShieldConfig['csp'] = {
enabled: false,
directives: {},
reportOnly: false,
}
export const csrf: ShieldConfig['csrf'] = {
enabled: Env.get('NODE_ENV') !== 'test',
exceptRoutes: [],
enableXsrfCookie: true,
methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
}
export const dnsPrefetch: ShieldConfig['dnsPrefetch'] = {
enabled: true,
allow: true,
}
export const xFrame: ShieldConfig['xFrame'] = {
enabled: true,
action: 'DENY',
}
export const hsts: ShieldConfig['hsts'] = {
enabled: true,
maxAge: '180 days',
includeSubDomains: true,
preload: false,
}
export const contentTypeSniffing: ShieldConfig['contentTypeSniffing'] = {
enabled: true,
}
`
)

await createRunner({
projectPath: fs.basePath,
patchers: [shieldConfig()],
}).run()

const content = await fs.contents('config/shield.ts')
assert.snapshot(content).matchInline(`
"
import { defineConfig } from '@adonisjs/shield'
export default defineConfig({
csp: {
enabled: false,
directives: {},
reportOnly: false,
},
csrf: {
enabled: Env.get('NODE_ENV') !== 'test',
exceptRoutes: [],
enableXsrfCookie: true,
methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
},
hsts: {
enabled: true,
maxAge: '180 days',
includeSubDomains: true,
preload: false,
},
contentTypeSniffing: {
enabled: true,
},
})
"
`)
})
})

0 comments on commit a6aa6b7

Please sign in to comment.