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
6 changes: 5 additions & 1 deletion packages/web-app-rclone-crypt/src/components/VaultSetup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { Resource, SpaceResource } from '@opencloud-eu/web-client'
import {
ResourceIcon,
useClientService,
PasswordPolicyRuleId,
usePasswordPolicyService,
useResourcesStore,
withoutExtension,
Expand Down Expand Up @@ -72,7 +73,10 @@ const resourcesStore = useResourcesStore()
const passwordPolicyService = usePasswordPolicyService()

// the passphrase never reaches the server, so only the client side rules of the policy apply
const passwordPolicy = passwordPolicyService.getPolicy({ enforcePassword: true })
const passwordPolicy = passwordPolicyService.getPolicy({
enforcePassword: true,
excludeRules: [PasswordPolicyRuleId.atMostCharacters]
})

function generatePassword() {
return passwordPolicyService.generatePassword()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ describe('VaultSetup', () => {
it('uses the password policy and the password generator for the password input', () => {
const { wrapper, mocks, passwordPolicy } = getWrapper()
const input = wrapper.findComponent<any>({ name: 'OcTextInput' })
expect(mocks.$passwordPolicyService.getPolicy).toHaveBeenCalledWith({ enforcePassword: true })
expect(mocks.$passwordPolicyService.getPolicy).toHaveBeenCalledWith({
enforcePassword: true,
excludeRules: ['atMostCharacters']
})
expect(input.props('passwordPolicy')).toBe(passwordPolicy)

mocks.$passwordPolicyService.generatePassword.mockReturnValue('generated-password')
Expand Down
34 changes: 29 additions & 5 deletions packages/web-pkg/src/services/passwordPolicy/passwordPolicy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ import { CapabilityStore } from '../../composables'
// @ts-ignore
import { PasswordPolicy } from 'password-sheriff'

export const PasswordPolicyRuleId = {
atLeastCharacters: 'atLeastCharacters',
atMostCharacters: 'atMostCharacters',
mustNotBeEmpty: 'mustNotBeEmpty',
atLeastUppercaseCharacters: 'atLeastUppercaseCharacters',
atLeastLowercaseCharacters: 'atLeastLowercaseCharacters',
atLeastDigits: 'atLeastDigits',
mustContain: 'mustContain'
} as const

export type PasswordPolicyRuleId = (typeof PasswordPolicyRuleId)[keyof typeof PasswordPolicyRuleId]

export interface PasswordPolicyOptions {
enforcePassword?: boolean
excludeRules?: PasswordPolicyRuleId[]
}

interface GeneratePasswordRules {
length: number
minLowercaseCharacters: number
Expand Down Expand Up @@ -82,8 +99,11 @@ export class PasswordPolicyService {
}
}

private buildPolicy({ enforcePassword = false } = {}): void {
const ruleset = {
private buildPolicy({
enforcePassword = false,
excludeRules = []
}: PasswordPolicyOptions = {}): void {
const ruleset: Record<PasswordPolicyRuleId, unknown> = {
atLeastCharacters: new AtLeastCharactersRule({ ...this.language }),
atMostCharacters: new AtMostCharactersRule({ ...this.language }),
mustNotBeEmpty: new MustNotBeEmptyRule({ ...this.language }),
Expand All @@ -92,7 +112,7 @@ export class PasswordPolicyService {
atLeastDigits: new AtLeastDigitsRule({ ...this.language }),
mustContain: new MustContainRule({ ...this.language })
}
const rules = {} as Record<string, unknown>
const rules = {} as Partial<Record<PasswordPolicyRuleId, unknown>>

if (enforcePassword && !this.hasRules()) {
rules.mustNotBeEmpty = {}
Expand Down Expand Up @@ -129,11 +149,15 @@ export class PasswordPolicyService {
}
}

for (const ruleId of excludeRules) {
delete rules[ruleId]
}

this.policy = new PasswordPolicy(rules, ruleset)
}

public getPolicy({ enforcePassword = false } = {}): PasswordPolicy {
this.buildPolicy({ enforcePassword })
public getPolicy(options: PasswordPolicyOptions = {}): PasswordPolicy {
this.buildPolicy(options)
return this.policy
}

Expand Down
16 changes: 15 additions & 1 deletion packages/web-pkg/tests/unit/services/passwordPolicy.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PasswordPolicyService } from '../../../src/services'
import { PasswordPolicyRuleId, PasswordPolicyService } from '../../../src/services'
import { createTestingPinia } from '@opencloud-eu/web-test-helpers'
import { Language } from 'vue3-gettext'
import { PasswordPolicyCapability } from '@opencloud-eu/web-client/ocs'
Expand Down Expand Up @@ -82,6 +82,20 @@ describe('PasswordPolicyService', () => {
expect(Object.keys(passwordPolicyService.getPolicy().rules)).toEqual(expected)
})
})
describe('excludeRules', () => {
it('leaves out the excluded rules', () => {
const { passwordPolicyService, store } = getWrapper({
min_characters: 2,
max_characters: 8
} as PasswordPolicyCapability)
passwordPolicyService.initialize(store)
const policy = passwordPolicyService.getPolicy({
excludeRules: [PasswordPolicyRuleId.atMostCharacters]
})
expect(Object.keys(policy.rules)).toEqual([PasswordPolicyRuleId.atLeastCharacters])
expect(policy.check('a'.repeat(20))).toBeTruthy()
})
})
describe('method "check"', () => {
describe('test the password correctly against te defined rules', () => {
it.each([
Expand Down
Loading