Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
76bc5fc
fix: redirect to correct dashboard
jamil314 Nov 10, 2025
92890fa
refactor: improve readability
jamil314 Nov 10, 2025
ab46494
refactor: use `filter...at(0)` instead of `find()`
jamil314 Nov 11, 2025
dad717e
fix: use flatMap()
jamil314 Nov 11, 2025
a6c1562
Merge pull request #10999 from opencrvs/ocrvs-10892
jamil314 Nov 11, 2025
1f065da
Merge branch 'develop' into v1.9.2-tmp
jamil314 Nov 11, 2025
23c1e69
fix: pass require config to address subfields
jamil314 Nov 12, 2025
456afbd
Merge pull request #11016 from opencrvs/ocrvs-10926
jamil314 Nov 12, 2025
378365d
Adds support for different certificate formats on certificate preview…
tareq89 Nov 13, 2025
f6e83d9
Merge branch develop into v1.9.2-tmp
jamil314 Nov 13, 2025
baa9ae7
Merge `develop` into `v1.9.2-tmp`
jamil314 Nov 13, 2025
cf66f94
Merge branch 'develop' into v1.9.2-tmp
jamil314 Nov 13, 2025
2a2b002
Merge branch 'develop' into v1.9.2-tmp
jamil314 Nov 13, 2025
43b5dc7
Merge branch 'develop' into v1.9.2-tmp
jamil314 Nov 17, 2025
0fbf63b
fix: show matched tracking ids in history dialog for duplicate action
jamil314 Nov 17, 2025
b675f4b
chore: bump version to 1.9.2
Zangetsu101 Nov 18, 2025
6a912c6
Merge branch 'v1.9.2-tmp' into ocrvs-10806
jamil314 Nov 18, 2025
092b7a9
fix(story): address not required
jamil314 Nov 18, 2025
9310cbc
Merge branch 'ocrvs-10806' of https://github.com/opencrvs/opencrvs-co…
jamil314 Nov 18, 2025
2713ec9
fix: add duplicate id in story
jamil314 Nov 18, 2025
f89f02a
Merge pull request #11056 from opencrvs/ocrvs-10806
jamil314 Nov 18, 2025
db88ed9
feat: allow using .location on HTTP
naftis Nov 27, 2025
dd8ddd1
refactor: also pick the Location href/pathname/hostname
naftis Nov 27, 2025
7cd9f58
fix cfg.body[k] getting overridden
naftis Nov 27, 2025
8ae7ea1
don't use Window to not need DOM
naftis Nov 27, 2025
4d2d50d
use window().location.get('href') helper
naftis Nov 27, 2025
89c2400
amend changelog
naftis Nov 27, 2025
af6eb0c
initial PoC commit for verifiable credentials
naftis Nov 28, 2025
97e2202
update k8s url
naftis Nov 28, 2025
2d93675
fix the bash shebang not being applied on build.sh
naftis Dec 1, 2025
f8647c3
implement image field
naftis Dec 1, 2025
479a9fb
Merge branch 'add-window-location-to-http' of https://github.com/open…
naftis Dec 1, 2025
8ac56d3
properly inform of a pending action
naftis Dec 2, 2025
3305fc9
make image not interactive to have it update on http
naftis Dec 2, 2025
befa5a0
add image fieldtype to indexing
naftis Dec 11, 2025
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: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@

HTTP input now accepts `field('..')` references in the HTTP body definition.

## 1.9.2

### New features

- Toolkit now exports `window().location.get` to country config that can be used as a template variable e.g. in HttpField request body.

## 1.9.1

### Breaking changes
Expand Down
1 change: 1 addition & 0 deletions license-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"packages/events/.kanelrc.js",
"packages/dashboards/data/metabase/*",
"packages/events/src/tests/extract-dump.sh",
"packages/toolkit/build.sh",
".kube"
],
"license": "license-header.txt",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"description": "OpenCRVS core workspace",
"license": "MPL-2.0",
"version": "1.9.0",
"version": "1.9.2",
"private": true,
"os": [
"darwin",
Expand Down
2 changes: 1 addition & 1 deletion packages/api-docs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencrvs/api-docs",
"version": "1.9.0",
"version": "1.9.2",
"description": "OpenCRVS API documentation",
"license": "MPL-2.0",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/auth/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencrvs/auth",
"version": "1.9.0",
"version": "1.9.2",
"description": "OpenCRVS authentication service",
"license": "MPL-2.0",
"private": true,
Expand Down
35 changes: 35 additions & 0 deletions packages/auth/src/features/authenticate/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,41 @@ export async function createTokenForActionConfirmation(
)
}

export async function createTokenForVerifiableCredentialIssuance(
eventId: UUID,
userId: string
) {
return sign(
{
scope: ['record.issue-vc'],
eventId,
userType: TokenUserType.enum.user
},
cert,
{
subject: userId,
algorithm: 'RS256',
expiresIn: '5 minutes',
audience: [
'opencrvs:gateway-user',
'opencrvs:user-mgnt-user',
'opencrvs:auth-user',
'opencrvs:hearth-user',
'opencrvs:notification-user',
'opencrvs:workflow-user',
'opencrvs:search-user',
'opencrvs:metrics-user',
'opencrvs:countryconfig-user',
'opencrvs:webhooks-user',
'opencrvs:config-user',
'opencrvs:documents-user',
'opencrvs:notification-api-user'
],
issuer: JWT_ISSUER
}
)
}

export async function storeUserInformation(
nonce: string,
userFullName: IUserName[],
Expand Down
14 changes: 12 additions & 2 deletions packages/auth/src/features/oauthToken/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,30 @@ import * as Hapi from '@hapi/hapi'
import { clientCredentialsHandler } from './client-credentials'
import * as oauthResponse from './responses'
import { tokenExchangeHandler } from './token-exchange'
import { preAuthorizedCodeHandler } from './pre-authorized-code'

const CLIENT_CREDENTIALS = 'client_credentials'
const TOKEN_EXCHANGE = 'urn:opencrvs:oauth:grant-type:token-exchange'
const PRE_AUTHORIZED_CODE_GRANT =
'urn:ietf:params:oauth:grant-type:pre-authorized_code'

export async function tokenHandler(
request: Hapi.Request,
h: Hapi.ResponseToolkit
) {
const grantType = request.query.grant_type

if (grantType === 'client_credentials') {
if (grantType === CLIENT_CREDENTIALS) {
return clientCredentialsHandler(request, h)
}

if (grantType === 'urn:opencrvs:oauth:grant-type:token-exchange') {
if (grantType === TOKEN_EXCHANGE) {
return tokenExchangeHandler(request, h)
}

if (grantType === PRE_AUTHORIZED_CODE_GRANT) {
return preAuthorizedCodeHandler(request, h)
}

return oauthResponse.invalidGrantType(h)
}
45 changes: 45 additions & 0 deletions packages/auth/src/features/oauthToken/pre-authorized-code.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* OpenCRVS is also distributed under the terms of the Civil Registration
* & Healthcare Disclaimer located at http://opencrvs.org/license.
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/

import * as Hapi from '@hapi/hapi'
import * as oauthResponse from './responses'
import { createTokenForVerifiableCredentialIssuance } from '../authenticate/service'

/**
* Issues a token for a pre-authorized code grant.
* This is used in OID4VC flows where a client has obtained a pre-authorized code to get the verifiable credential.
*/
export async function preAuthorizedCodeHandler(
request: Hapi.Request,
h: Hapi.ResponseToolkit
) {
const preAuthorizedCode = request.query?.['pre-authorized_code'] // for PoC: this is event ID

if (!preAuthorizedCode) {
return oauthResponse.invalidRequest(h, 'missing pre-authorized_code')
}

// const token = request.headers.authorization.replace('Bearer ', '')
// const decodedOrError = pipe(token, verifyToken)

// if (decodedOrError._tag === 'Left') {
// return oauthResponse.invalidSubjectToken(h)
// }

// const { sub } = decodedOrError.right

const token = await createTokenForVerifiableCredentialIssuance(
preAuthorizedCode,
'anonymous-user' // In PoC, no user binding, see above comment when needed
)

return oauthResponse.preAuthorizedCodeSuccess(h, token)
}
21 changes: 18 additions & 3 deletions packages/auth/src/features/oauthToken/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
*/
import * as Hapi from '@hapi/hapi'

export const invalidRequest = (h: Hapi.ResponseToolkit) =>
export const invalidRequest = (
h: Hapi.ResponseToolkit,
description = 'Invalid request. Check that all required parameters have been provided.'
) =>
h
.response({
error: 'invalid_request',
error_description:
'Invalid request. Check that all required parameters have been provided.',
error_description: description,
error_uri:
'Refer to https://documentation.opencrvs.org/technology/interoperability/authenticate-a-client'
})
Expand Down Expand Up @@ -62,3 +64,16 @@ export const success = (h: Hapi.ResponseToolkit, token: string) =>
})
.header('Cache-Control', 'no-store')
.code(200)

export const preAuthorizedCodeSuccess = (
h: Hapi.ResponseToolkit,
token: string
) =>
h
.response({
access_token: token,
token_type: 'Bearer',
expires_in: 300 // 5 minutes
})
.header('Cache-Control', 'no-store')
.code(200)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* OpenCRVS is also distributed under the terms of the Civil Registration
* & Healthcare Disclaimer located at http://opencrvs.org/license.
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/

import { env } from '@auth/environment'
import * as Hapi from '@hapi/hapi'

// @TODO: What is actually the best way to figure this out?
// - [ ] should we pass a new environment variable?
// - [ ] should this live not in auth?
const GATEWAY = env.isProduction
? `https://gateway.${env.DOMAIN}`
: 'http://localhost:7070'

export function openidCredentialIssuerHandler(
request: Hapi.Request,
h: Hapi.ResponseToolkit
) {
return h.response({
credential_issuer: GATEWAY,
credential_endpoint: `${GATEWAY}/events/openid4vc.issuance.credential`,
token_endpoint: `${GATEWAY}/auth/token`,

credential_configurations_supported: {
BirthCertificateCredential: {
format: 'jwt_vc_json'
// claim schema etc...
}
}
})
}
11 changes: 10 additions & 1 deletion packages/auth/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ import reindexingTokenHandler, {
responseSchema as reindexResponseSchema
} from './features/reindexToken/handler'
import { Boom, badRequest } from '@hapi/boom'
import { openidCredentialIssuerHandler } from './features/openid4vc/well-known-openid-credentials'

export type AuthServer = {
server: Hapi.Server
Expand Down Expand Up @@ -128,7 +129,15 @@ export async function createServer() {
server.route({
method: 'GET',
path: '/.well-known',
handler: getPublicKey,
handler: (_, h) => h.response(getPublicKey()).type('text/plain'),
options: {
tags: ['api']
}
})
server.route({
method: 'GET',
path: '/.well-known/openid-credential-issuer',
handler: openidCredentialIssuerHandler,
options: {
tags: ['api']
}
Expand Down
2 changes: 1 addition & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opencrvs/client",
"version": "1.9.0",
"version": "1.9.2",
"description": "OpenCRVS client application",
"license": "MPL-2.0",
"private": true,
Expand Down
23 changes: 18 additions & 5 deletions packages/client/src/hooks/useHomePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,23 @@ export const useHomePage = () => {
const { pathname } = useLocation()
const { routes } = useNavigation()
const userDetails = useSelector(getUserDetails)
const firstNavItem = routes
.filter((navigationGroup) => navigationGroup.tabs.length > 0)
.at(0)
?.tabs.at(0)?.name

const firstDashboard = window.config.DASHBOARDS?.at(0)?.id

const tabs = routes.flatMap((navigationGroup) => navigationGroup.tabs)

const firstNavItem = tabs
.filter((tab) => {
if (
tab.name === WORKQUEUE_TABS.dashboard &&
window.config.DASHBOARDS.length === 0
) {
// ignores dashboard tab when no dashboard is configured
return false
}
return true
})
.at(0)?.name

let path: string | Partial<Path> = REGISTRAR_HOME

Expand Down Expand Up @@ -76,7 +89,7 @@ export const useHomePage = () => {
path = ALL_USER_EMAIL
break
case WORKQUEUE_TABS.dashboard:
path = DASHBOARD
path = formatUrl(DASHBOARD, { id: firstDashboard! })
break
case WORKQUEUE_TABS.performance:
path = generatePerformanceHomeUrl({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ export const DisabledFormFields: StoryObj<typeof FormFieldGenerator> = {

// in react-select v5 literal inputs are not rendered when disabled, so we ensure the fields are there.
await canvas.findByLabelText('Region')
await canvas.findByLabelText('District *')
await canvas.findByLabelText('District')
})
}
}
Expand Down Expand Up @@ -559,7 +559,7 @@ export const EnabledFormFields: StoryObj<typeof FormFieldGenerator> = {
}

await canvas.findByLabelText('Region')
await canvas.findByLabelText('District *')
await canvas.findByLabelText('District')
})
}
}
Expand Down Expand Up @@ -647,9 +647,7 @@ export const EnabledFormFieldsByEnableCondition: StoryObj<
}

await expect(await canvas.findByLabelText('Region')).not.toBeDisabled()
await expect(
await canvas.findByLabelText('District *')
).not.toBeDisabled()
await expect(await canvas.findByLabelText('District')).not.toBeDisabled()
})

await step('All form fields should be disabled again', async () => {
Expand All @@ -674,7 +672,7 @@ export const EnabledFormFieldsByEnableCondition: StoryObj<

// in react-select v5 literal inputs are not rendered when disabled, so we ensure the fields are there.
await canvas.findByLabelText('Region')
await canvas.findByLabelText('District *')
await canvas.findByLabelText('District')
}
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ import {
isIdReaderFieldType,
isQrReaderFieldType,
isLoaderFieldType,
isAgeFieldType
isAgeFieldType,
isImageFieldType
} from '@opencrvs/commons/client'
import { TextArea } from '@opencrvs/components/lib/TextArea'
import { InputField } from '@client/components/form/InputField'
Expand All @@ -87,7 +88,8 @@ import {
AlphaPrintButton,
Http,
LinkButton,
VerificationStatus
VerificationStatus,
Image
} from '@client/v2-events/features/events/registered-fields'
import { Address } from '@client/v2-events/features/events/registered-fields/Address'
import { Data } from '@client/v2-events/features/events/registered-fields/Data'
Expand Down Expand Up @@ -800,6 +802,17 @@ export const GeneratedInputField = React.memo(
)
}

if (isImageFieldType(field)) {
return (
field.value && (
<Image.Input
alt={field.config.configuration.alt}
value={field.value}
/>
)
)
}

throw new Error(`Unsupported field ${JSON.stringify(fieldDefinition)}`)
}
)
Expand Down
Loading
Loading