Skip to content

Commit

Permalink
Merge branch 'main' into service-portal/notifications-locale-cleanstring
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Jun 14, 2024
2 parents 5a25e30 + 223783c commit b965cea
Show file tree
Hide file tree
Showing 53 changed files with 2,452 additions and 123 deletions.
2 changes: 1 addition & 1 deletion apps/native/app/src/components/offline/offline-banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Animated, Easing, SafeAreaView } from 'react-native'
import { Navigation } from 'react-native-navigation'
import styled from 'styled-components/native'
import { getIntl } from '../../contexts/i18n-provider'
import { useOfflineActions, useOfflineStore } from '../../stores/offline-store'
import { useOfflineActions } from '../../stores/offline-store'
import { ComponentRegistry as CR } from '../../utils/component-registry'

const TranslateYValue = 200
Expand Down
12 changes: 2 additions & 10 deletions apps/native/app/src/hoc/offline-hoc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ export const OfflineHoc = ({ children }: OfflineHocProps) => {
const lockScreenActivatedAt = useAuthStore(
({ lockScreenActivatedAt }) => lockScreenActivatedAt,
)
const userInfo = useAuthStore(({ userInfo }) => userInfo)

useEffect(() => {
if (
bannerVisible &&
!bannerHasBeenShown &&
!isConnected &&
!lockScreenActivatedAt &&
userInfo
lockScreenActivatedAt === null
) {
void impactAsync(ImpactFeedbackStyle.Heavy)
void Navigation.showOverlay({
Expand All @@ -39,13 +37,7 @@ export const OfflineHoc = ({ children }: OfflineHocProps) => {
})
setBannerHasBeenShown(true)
}
}, [
bannerVisible,
bannerHasBeenShown,
isConnected,
lockScreenActivatedAt,
userInfo,
])
}, [bannerVisible, bannerHasBeenShown, isConnected, lockScreenActivatedAt])

return <>{children}</>
}
9 changes: 6 additions & 3 deletions apps/native/app/src/screens/app-lock/app-lock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,18 @@ export const AppLockScreen: NavigationFunctionComponent<{
lockScreenComponentId: undefined,
}))
}, [])

const unlockApp = useCallback(() => {
Animated.spring(av, {
toValue: 0,
useNativeDriver: true,
delay: 100,
}).start(() => {
resetLockScreen()
void Navigation.dismissAllOverlays()
// We want to reset lockScreenActivatedAt to null here to trigger offline banner if offline
authStore.setState(() => ({
lockScreenActivatedAt: null,
lockScreenComponentId: undefined,
}))
void Navigation.dismissOverlay(componentId)
av.setValue(1)
})
}, [componentId])
Expand Down
1 change: 1 addition & 0 deletions apps/native/app/src/screens/inbox/inbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ export const InboxScreen: NavigationFunctionComponent<{
padding: 16,
flexDirection: 'row',
gap: 8,
minHeight: 76,
}}
>
<SearchBar
Expand Down
2 changes: 1 addition & 1 deletion apps/native/app/src/screens/more/personal-info.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const PersonalInfoScreen: NavigationFunctionComponent = ({
const { dismiss, dismissed } = usePreferencesStore()
const natRegRes = useNationalRegistryUserQuery()
const natRegData = natRegRes?.data?.nationalRegistryUser
const errorNatReg = !!natRegRes.error
const errorNatReg = !!natRegRes.error && !natRegData
const loadingNatReg = natRegRes.loading && !natRegData

return (
Expand Down
4 changes: 1 addition & 3 deletions apps/native/app/src/stores/auth-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ import {
revoke,
} from 'react-native-app-auth'
import Keychain from 'react-native-keychain'
import { Navigation } from 'react-native-navigation'
import createUse from 'zustand'
import create, { State } from 'zustand/vanilla'
import { bundleId, getConfig } from '../config'
import { getIntl } from '../contexts/i18n-provider'
import { getApolloClientAsync } from '../graphql/client'
import { isAndroid } from '../utils/devices'
import { getAppRoot } from '../utils/lifecycle/get-app-root'
import { offlineStore } from './offline-store'
import { preferencesStore } from './preferences-store'
import { clearAllStorages } from '../stores/mmkv'
Expand All @@ -36,7 +34,7 @@ interface UserInfo {
interface AuthStore extends State {
authorizeResult: AuthorizeResult | RefreshResult | undefined
userInfo: UserInfo | undefined
lockScreenActivatedAt: number | undefined
lockScreenActivatedAt?: number | null
lockScreenComponentId: string | undefined
noLockScreenUntilNextAppStateActive: boolean
isCogitoAuth: boolean
Expand Down
55 changes: 22 additions & 33 deletions apps/services/auth/ids-api/infra/ids-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ import { UserProfileScope } from '../../../../../libs/auth/scopes/src/lib/userPr
const namespace = 'identity-server'
const imageName = 'services-auth-ids-api'

const REDIS_NODE_CONFIG = {
dev: json([
'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379',
]),
staging: json([
'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379',
]),
prod: json([
'clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379',
]),
}

export const serviceSetup = (): ServiceBuilder<'services-auth-ids-api'> => {
return service('services-auth-ids-api')
.namespace(namespace)
Expand Down Expand Up @@ -39,39 +51,9 @@ export const serviceSetup = (): ServiceBuilder<'services-auth-ids-api'> => {
staging: 'IS-TEST/GOV/6503760649/SKRA-Protected/Einstaklingar-v1',
prod: 'IS/GOV/6503760649/SKRA-Protected/Einstaklingar-v1',
},
XROAD_NATIONAL_REGISTRY_REDIS_NODES: {
dev: json([
'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379',
]),
staging: json([
'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379',
]),
prod: json([
'clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379',
]),
},
COMPANY_REGISTRY_REDIS_NODES: {
dev: json([
'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379',
]),
staging: json([
'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379',
]),
prod: json([
'clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379',
]),
},
XROAD_RSK_PROCURING_REDIS_NODES: {
dev: json([
'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379',
]),
staging: json([
'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379',
]),
prod: json([
'clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379',
]),
},
XROAD_NATIONAL_REGISTRY_REDIS_NODES: REDIS_NODE_CONFIG,
COMPANY_REGISTRY_REDIS_NODES: REDIS_NODE_CONFIG,
XROAD_RSK_PROCURING_REDIS_NODES: REDIS_NODE_CONFIG,
COMPANY_REGISTRY_XROAD_PROVIDER_ID: {
dev: 'IS-DEV/GOV/10006/Skatturinn/ft-v1',
staging: 'IS-TEST/GOV/5402696029/Skatturinn/ft-v1',
Expand All @@ -88,13 +70,20 @@ export const serviceSetup = (): ServiceBuilder<'services-auth-ids-api'> => {
staging: 'false',
prod: 'false',
},
PASSKEY_CORE_RP_ID: 'island.is',
PASSKEY_CORE_RP_NAME: 'Island.is',
PASSKEY_CORE_CHALLENGE_TTL_MS: '120000',
REDIS_NODES: REDIS_NODE_CONFIG,
})
.secrets({
IDENTITY_SERVER_CLIENT_SECRET:
'/k8s/services-auth/IDENTITY_SERVER_CLIENT_SECRET',
NOVA_URL: '/k8s/services-auth/NOVA_URL',
NOVA_USERNAME: '/k8s/services-auth/NOVA_USERNAME',
NOVA_PASSWORD: '/k8s/services-auth/NOVA_PASSWORD',
PASSKEY_CORE_ALLOWED_ORIGINS:
'/k8s/services-auth/PASSKEY_CORE_ALLOWED_ORIGINS',
PASSKEY_CORE_MAX_AGE_DAYS: '/k8s/services-auth/PASSKEY_CORE_MAX_AGE_DAYS',
NATIONAL_REGISTRY_B2C_CLIENT_SECRET:
'/k8s/services-auth/NATIONAL_REGISTRY_B2C_CLIENT_SECRET',
})
Expand Down
4 changes: 4 additions & 0 deletions apps/services/auth/ids-api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SequelizeModule } from '@nestjs/sequelize'

import {
DelegationConfig,
PasskeysCoreConfig,
SequelizeConfigService,
} from '@island.is/auth-api-lib'
import { AuthModule } from '@island.is/auth-nest-tools'
Expand Down Expand Up @@ -31,6 +32,7 @@ import { ResourcesModule } from './resources/resources.module'
import { TranslationModule } from './translation/translation.module'
import { UserProfileModule } from './user-profile/user-profile.module'
import { UsersModule } from './users/users.module'
import { PasskeysModule } from './passkeys/passkeys.module'

@Module({
imports: [
Expand All @@ -50,6 +52,7 @@ import { UsersModule } from './users/users.module'
UserProfileModule,
NotificationsModule,
LoginRestrictionsModule,
PasskeysModule,
ConfigModule.forRoot({
isGlobal: true,
load: [
Expand All @@ -61,6 +64,7 @@ import { UsersModule } from './users/users.module'
RskRelationshipsClientConfig,
UserProfileClientConfig,
XRoadConfig,
PasskeysCoreConfig,
NationalRegistryV3ClientConfig,
],
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ApiProperty } from '@nestjs/swagger'

import { IsBoolean, IsOptional, IsString } from 'class-validator'

export class AuthenticationOptions {
@IsString()
@ApiProperty()
passkey: string
}

export class AuthenticationResult {
@IsBoolean()
@ApiProperty()
verified!: boolean

@IsString()
@ApiProperty()
idp!: string

@IsString()
@ApiProperty()
sub!: string
}
55 changes: 55 additions & 0 deletions apps/services/auth/ids-api/src/app/passkeys/passkeys.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {
BadRequestException,
Body,
Controller,
Post,
UseGuards,
VERSION_NEUTRAL,
} from '@nestjs/common'
import { ApiCreatedResponse, ApiTags } from '@nestjs/swagger'

import { PasskeysCoreService } from '@island.is/auth-api-lib'
import { Documentation } from '@island.is/nest/swagger'
import {
AuthenticationOptions,
AuthenticationResult,
} from './dto/authenticationOptions.dto'
import { IdsAuthGuard, ScopesGuard } from '@island.is/auth-nest-tools'
import { Audit } from '@island.is/nest/audit'
import {
FeatureFlag,
FeatureFlagGuard,
Features,
} from '@island.is/nest/feature-flags'

const namespace = '@island.is/auth/ids-api/passkeys'

@ApiTags('passkeys')
@Controller({
path: 'passkeys',
version: ['1', VERSION_NEUTRAL],
})
@UseGuards(IdsAuthGuard, ScopesGuard, FeatureFlagGuard)
@Audit({ namespace })
export class PasskeysController {
constructor(private readonly passkeysCoreService: PasskeysCoreService) {}

@Post('authenticate')
@Documentation({
summary:
'Validates passkey authentication based on input from authenticated user.',
description: 'Verifies authenticated user passkey authentication response.',
response: { status: 200, type: AuthenticationResult },
})
@ApiCreatedResponse({ type: AuthenticationResult })
@Audit<AuthenticationResult>({
resources: (authenticationResult) =>
authenticationResult.verified.toString(),
})
@FeatureFlag(Features.isPasskeyAuthEnabled)
async verifyAuthentication(
@Body() body: AuthenticationOptions,
): Promise<AuthenticationResult> {
return this.passkeysCoreService.verifyAuthenticationString(body.passkey)
}
}
16 changes: 16 additions & 0 deletions apps/services/auth/ids-api/src/app/passkeys/passkeys.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common'
import { PasskeysController } from './passkeys.controller'
import { PasskeysCoreConfig, PasskeysCoreModule } from '@island.is/auth-api-lib'

import { FeatureFlagModule } from '@island.is/nest/feature-flags'

@Module({
imports: [
PasskeysCoreConfig.registerOptional(),
PasskeysCoreModule,
FeatureFlagModule,
],
controllers: [PasskeysController],
providers: [],
})
export class PasskeysModule {}
42 changes: 20 additions & 22 deletions apps/services/auth/public-api/infra/auth-public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@ import { service, ServiceBuilder } from '../../../../../infra/src/dsl/dsl'
import { json } from '../../../../../infra/src/dsl/dsl'
import { Base, Client, RskProcuring } from '../../../../../infra/src/dsl/xroad'

const REDIS_NODE_CONFIG = {
dev: json([
'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379',
]),
staging: json([
'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379',
]),
prod: json([
'clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379',
]),
}

export const serviceSetup = (): ServiceBuilder<'services-auth-public-api'> => {
return service('services-auth-public-api')
.namespace('identity-server-admin')
Expand All @@ -27,39 +39,25 @@ export const serviceSetup = (): ServiceBuilder<'services-auth-public-api'> => {
staging: 'IS-TEST/GOV/6503760649/SKRA-Protected/Einstaklingar-v1',
prod: 'IS/GOV/6503760649/SKRA-Protected/Einstaklingar-v1',
},
XROAD_NATIONAL_REGISTRY_REDIS_NODES: {
dev: json([
'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379',
]),
staging: json([
'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379',
]),
prod: json([
'clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379',
]),
},
XROAD_RSK_PROCURING_REDIS_NODES: {
dev: json([
'clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379',
]),
staging: json([
'clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379',
]),
prod: json([
'clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379',
]),
},
XROAD_NATIONAL_REGISTRY_REDIS_NODES: REDIS_NODE_CONFIG,
XROAD_RSK_PROCURING_REDIS_NODES: REDIS_NODE_CONFIG,
XROAD_TJODSKRA_MEMBER_CODE: {
prod: '6503760649',
dev: '10001',
staging: '6503760649',
},
PASSKEY_CORE_RP_ID: 'island.is',
PASSKEY_CORE_RP_NAME: 'Island.is',
PASSKEY_CORE_CHALLENGE_TTL_MS: '120000',
REDIS_NODES: REDIS_NODE_CONFIG,
})
.secrets({
IDENTITY_SERVER_CLIENT_SECRET:
'/k8s/services-auth/IDENTITY_SERVER_CLIENT_SECRET',
NATIONAL_REGISTRY_IDS_CLIENT_SECRET:
'/k8s/xroad/client/NATIONAL-REGISTRY/IDENTITYSERVER_SECRET',
PASSKEY_CORE_ALLOWED_ORIGINS:
'/k8s/services-auth/PASSKEY_CORE_ALLOWED_ORIGINS',
})
.xroad(Base, Client, RskProcuring)
.ingress({
Expand Down
Loading

0 comments on commit b965cea

Please sign in to comment.