Skip to content

Commit

Permalink
Merge pull request #755 from digitalfabrik/pre-release
Browse files Browse the repository at this point in the history
Prerelease
  • Loading branch information
sarahsporck committed Feb 27, 2023
2 parents 3af1ded + 359a671 commit 641092b
Show file tree
Hide file tree
Showing 22 changed files with 419 additions and 271 deletions.
4 changes: 2 additions & 2 deletions administration/src/cards/PdfFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function fillCodeArea(qrCode: PdfQrCode, x: number, y: number, size: number, pag

export async function generatePdf(
dynamicCodes: DynamicActivationCode[],
staticCodes: StaticVerificationCode[] | null,
staticCodes: StaticVerificationCode[],
region: Region,
pdfConfig: PdfConfig
) {
Expand All @@ -143,7 +143,7 @@ export async function generatePdf(
? await PDFDocument.load(await fetch(pdfConfig.templatePath).then(res => res.arrayBuffer()))
: null

if (staticCodes !== null && dynamicCodes.length !== staticCodes.length) {
if (staticCodes.length !== 0 && dynamicCodes.length !== staticCodes.length) {
throw new Error('Activation codes count does not match static codes count.')
}

Expand Down
52 changes: 0 additions & 52 deletions administration/src/cards/activation.ts

This file was deleted.

40 changes: 40 additions & 0 deletions administration/src/cards/creation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { DynamicActivationCode, StaticVerificationCode } from '../generated/card_pb'
import {
AddCardsDocument,
AddCardsMutation,
AddCardsMutationVariables,
CardGenerationModelInput,
CodeType,
Region,
} from '../generated/graphql'
import hashCardInfo from './hashCardInfo'
import { ApolloClient } from '@apollo/client'
import { uint8ArrayToBase64 } from '../util/base64'

type Codes = (DynamicActivationCode | StaticVerificationCode)[]

export async function createCards(client: ApolloClient<object>, activationCodes: Codes, region: Region) {
const cards: CardGenerationModelInput[] = await Promise.all(
activationCodes.map(async code => {
const codeType = code instanceof DynamicActivationCode ? CodeType.Dynamic : CodeType.Static
const cardInfoHash = await hashCardInfo(code.info!, code.pepper)
const expirationDay = code.info!.expirationDay
const activationSecretBase64 =
code instanceof DynamicActivationCode ? uint8ArrayToBase64(code.activationSecret) : null
return {
cardExpirationDay: expirationDay ?? null, // JS number can represent integers up to 2^53, so it can represent all values of an uint32 (protobuf)
cardInfoHashBase64: uint8ArrayToBase64(cardInfoHash),
activationSecretBase64: activationSecretBase64,
regionId: region.id,
codeType,
}
})
)
const result = await client.mutate<AddCardsMutation, AddCardsMutationVariables>({
mutation: AddCardsDocument,
variables: { cards },
})
if (!result.data?.success) {
throw Error(JSON.stringify(result))
}
}
13 changes: 6 additions & 7 deletions administration/src/components/cards/CreateCardsController.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useState } from 'react'
import { useContext, useState } from 'react'
import { Spinner } from '@blueprintjs/core'
import { CardBlueprint } from '../../cards/CardBlueprint'
import CreateCardsForm from './CreateCardsForm'
Expand All @@ -7,10 +7,10 @@ import { useAppToaster } from '../AppToaster'
import GenerationFinished from './CardsCreatedMessage'
import downloadDataUri from '../../util/downloadDataUri'
import { WhoAmIContext } from '../../WhoAmIProvider'
import { createCards } from '../../cards/activation'
import { createCards } from '../../cards/creation'
import { ProjectConfigContext } from '../../project-configs/ProjectConfigContext'
import { CodeType, Region } from '../../generated/graphql'
import { generatePdf } from '../../cards/PdfFactory'
import { Region } from '../../generated/graphql'

enum CardActivationState {
input,
Expand Down Expand Up @@ -51,13 +51,12 @@ const InnerCreateCardsController = ({ region }: { region: Region }) => {
? cardBlueprints.map(cardBlueprints => {
return cardBlueprints.generateStaticVerificationCode()
})
: null
: []

const pdfDataUri = await generatePdf(dynamicCodes, staticCodes, region, projectConfig.pdf)

await createCards(client, dynamicCodes, region, CodeType.Dynamic)

if (staticCodes) await createCards(client, staticCodes, region, CodeType.Static)
const codes = [...dynamicCodes, ...staticCodes]
await createCards(client, codes, region)

downloadDataUri(pdfDataUri, 'berechtigungskarten.pdf')
setState(CardActivationState.finished)
Expand Down
4 changes: 2 additions & 2 deletions administration/src/graphql/verification/addCard.graphql
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
mutation addCard($card: CardGenerationModelInput!) {
success: addCard(card: $card)
mutation addCards($cards: [CardGenerationModelInput!]!) {
success: addCards(cards: $cards)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,34 +19,38 @@ import java.util.Base64

@Suppress("unused")
class CardMutationService {
@GraphQLDescription("Stores a new digital entitlement card")
fun addCard(dfe: DataFetchingEnvironment, card: CardGenerationModel): Boolean {
@GraphQLDescription("Stores a batch of new digital entitlementcards")
fun addCards(dfe: DataFetchingEnvironment, cards: List<CardGenerationModel>): Boolean {
val jwtPayload = dfe.getContext<GraphQLContext>().enforceSignedIn()

if (!validateNewCard(card)) throw Exception("Card invalid.")

transaction {
val user =
AdministratorEntity.findById(jwtPayload.adminId)
?: throw UnauthorizedException()
val targetedRegionId = card.regionId
if (!Authorizer.mayCreateCardInRegion(user, targetedRegionId)) {
throw UnauthorizedException()
}
val activationSecret =
card.activationSecretBase64?.let {
val decodedRawActivationSecret = Base64.getDecoder().decode(it)
CardActivator.hashActivationSecret(decodedRawActivationSecret)

for (card in cards) {
val targetedRegionId = card.regionId
if (!Authorizer.mayCreateCardInRegion(user, targetedRegionId)) {
throw UnauthorizedException()
}
if (!validateNewCard(card)) {
throw Exception("Invalid cart.")
}
val activationSecret =
card.activationSecretBase64?.let {
val decodedRawActivationSecret = Base64.getDecoder().decode(it)
CardActivator.hashActivationSecret(decodedRawActivationSecret)
}

CardRepository.insert(
Base64.getDecoder().decode(card.cardInfoHashBase64),
activationSecret,
card.cardExpirationDay,
card.regionId,
user.id.value,
card.codeType,
)
CardRepository.insert(
Base64.getDecoder().decode(card.cardInfoHashBase64),
activationSecret,
card.cardExpirationDay,
card.regionId,
user.id.value,
card.codeType
)
}
}
return true
}
Expand Down
5 changes: 5 additions & 0 deletions frontend/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ android {

buildTypes {
release {
ndk {
// Flutter does not support x86, so we exclude it in the following list: https://github.com/flutter/flutter/issues/9253
abiFilters 'armeabi-v7a','arm64-v8a','x86_64'
}

if (localProperties.containsKey("signing.keyAlias")) {
signingConfig signingConfigs.localProps
} else {
Expand Down
Loading

0 comments on commit 641092b

Please sign in to comment.