Compare commits

...

44 Commits

Author SHA1 Message Date
Hauke Tönjes 28d91f1b3b
Upgrade to next12
- Use latest stable versions of all dependencies
2022-04-15 10:44:21 +02:00
Marvin Sextro 68387b1eae
Merge pull request #157 from covidpass-org/dev
Romanian translation and minor fixes
2022-01-10 04:38:42 +01:00
Marvin Sextro 685bbcb19b Increase timeout 2022-01-10 04:29:20 +01:00
Marvin Sextro 7d930105d2 Try to fix QR code viewer 2022-01-10 04:19:41 +01:00
Marvin Sextro d205444659 Try to fix buttons 2022-01-10 04:04:29 +01:00
Marvin Sextro 822e8fcd4c Integrate Romanian translation 2022-01-10 03:24:34 +01:00
Marvin Sextro 53c81eb9e5
Merge pull request #153 from KoNickss/dev
[localisation] Added RO locale
2022-01-10 03:15:07 +01:00
Marvin Sextro 2a9bdd86d7 Improve QR code viewer and try to fix buttons 2022-01-10 03:10:40 +01:00
po 87a990e146
Added RO locale 2022-01-06 01:08:22 +02:00
Marvin Sextro 9534a5d5e3
Merge pull request #147 from covidpass-org/dev
QR code viewer and content improvements
2021-12-29 03:31:26 +01:00
Marvin Sextro b8eae1fb54 QR code viewer and content improvements 2021-12-29 03:29:07 +01:00
Marvin Sextro e765408e5a
Merge pull request #144 from covidpass-org/dev
Improve QR code viewer
2021-12-29 01:28:06 +01:00
Marvin Sextro 931b0806f9 Scroll down after successful pass creation 2021-12-29 01:11:13 +01:00
Marvin Sextro 4f30b9b326 Fix greek translation 2021-12-29 00:57:06 +01:00
Marvin Sextro 3b04e24a6b Improve QR code viewer 2021-12-29 00:53:31 +01:00
Marvin Sextro 40397d2fea
Merge pull request #142 from covidpass-org/dev
Added QR code viewer and fixed button behavior
2021-12-27 19:14:49 +01:00
Marvin Sextro 64f473d214 Added QR code viewer and fixed button behavior 2021-12-27 19:06:31 +01:00
Marvin Sextro 22a54fcb9c
Merge pull request #141 from covidpass-org/dev
Dev
2021-12-26 13:08:56 +01:00
Marvin Sextro 1cbaccdf82 Rename test results 2021-12-26 00:18:56 +01:00
Marvin Sextro d1da98a9e4 Improve add to wallet button 2021-12-25 23:58:45 +01:00
Marvin Sextro 1eb6bea1a6 Add alt text and credits to pass 2021-12-25 22:07:03 +01:00
Marvin Sextro c106be369f
Merge pull request #140 from covidpass-org/localization
Fix swedish translation
2021-12-25 21:17:31 +01:00
Marvin Sextro bc3efc4728
Merge pull request #136 from julien1619/patch-1
Fix decoder for third dose - fixes #124
2021-12-25 21:10:35 +01:00
Marvin Sextro b349653721 Use Node.js 16 in Dockerfile 2021-12-25 21:07:45 +01:00
Marvin Sextro 59e079f27e Downgrade Next.js 2021-12-25 19:24:23 +01:00
Marvin Sextro 47cd07a59d Fix swedish translation 2021-12-23 01:19:42 +01:00
Marvin Sextro eeed18bbc4
Merge pull request #139 from covidpass-org/main
Update dependencies
2021-12-23 01:18:16 +01:00
Julien Blatecky 674d325502
Fix decoder for third dose 2021-12-10 14:18:10 +01:00
Hauke Tönjes 48028bb211
Update dependencies 2021-12-10 12:31:45 +01:00
Marvin Sextro 4f80dcf33c
Merge pull request #128 from covidpass-org/dev
Swedish translation and layout improvements
2021-12-02 04:07:09 +01:00
Marvin Sextro 8746d3c400 Fix translation source 2021-12-02 03:57:00 +01:00
Marvin Sextro c12e0f5d2e Add translations for the share button 2021-12-02 03:45:02 +01:00
Marvin Sextro be72026d54 Add share and support buttons 2021-12-02 03:06:24 +01:00
Marvin Sextro 240f73ab5f Remove unnecessary hint 2021-12-02 01:18:02 +01:00
Marvin Sextro d07c6ae232
Merge pull request #127 from covidpass-org/localization
Localization
2021-12-02 01:16:24 +01:00
Marvin Sextro 0c0ddf2a47
Merge pull request #126 from nilaallj/localization
Full Swedish translation
2021-12-02 01:13:59 +01:00
Marvin Sextro 22c00b4052 Added browser warning and minor layout and content improvements 2021-12-02 01:02:20 +01:00
Marvin Sextro 790bdf4494 Remove duplicate dependencies from lock file 2021-12-02 00:58:29 +01:00
Marvin Sextro 1aee8b8d86 Merge branch 'main' into dev 2021-12-02 00:52:26 +01:00
nilaallj 9b0a0a4b81 Full Swedish translation 2021-12-01 21:29:18 +01:00
Marvin Sextro 50d3830fec
Merge pull request #121 from covidpass-org/next12
Upgrade to Next.js 12
2021-11-21 22:48:32 +01:00
Hauke Tönjes ecaa891a40
Upgrade packages 2021-09-03 14:26:41 +02:00
iBobo 1949060709
Support JPEG and other image formats; remove pngjs dependency (#93)
* Support JPEG and other image formats; remove pngjs

By using native Canvas to render images it was possible to remove
dependency on external libraries to support image formats while
supporting more formats like JPEG, GIF and WEBP for the QR image

* Constrain images to 2 Mpx

Co-authored-by: Marvin Sextro <marvin.sextro@gmail.com>
2021-09-03 14:05:18 +02:00
Hauke Tönjes 03a00ea5cb
Upgrade packages (#86)
Co-authored-by: Marvin Sextro <marvin.sextro@gmail.com>
2021-08-30 22:14:32 +02:00
44 changed files with 1034 additions and 2306 deletions

View File

@ -1,5 +1,5 @@
# Install dependencies only when needed
FROM node:14-alpine AS deps
FROM node:16-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
@ -7,14 +7,14 @@ COPY package.json ./
RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed
FROM node:14-alpine AS builder
FROM node:16-alpine AS builder
WORKDIR /app
COPY . .
COPY --from=deps /app/node_modules ./node_modules
RUN yarn build
# Production image, copy all the files and run next
FROM node:14-alpine AS runner
FROM node:16-alpine AS runner
WORKDIR /app
ENV NODE_ENV production

View File

@ -1,24 +1,22 @@
import {useTranslation} from 'next-i18next';
interface AlertProps {
onClose: () => void;
errorMessage: string;
message: string;
isWarning: boolean;
}
function Alert(props: AlertProps): JSX.Element {
const { t } = useTranslation(['index', 'errors']);
return (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 mt-5 rounded relative" role="alert">
<span className="block sm:inline pr-6" id="message">{props.errorMessage}</span>
<span className="absolute top-0 bottom-0 right-0 px-4 py-3" onClick={props.onClose}>
<svg className="fill-current h-6 w-6 text-red-500" role="button" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20">
<title>{t('index:errorClose')}</title>
<path
d="M14.348 14.849a1.2 1.2 0 0 1-1.697 0L10 11.819l-2.651 3.029a1.2 1.2 0 1 1-1.697-1.697l2.758-3.15-2.759-3.152a1.2 1.2 0 1 1 1.697-1.697L10 8.183l2.651-3.031a1.2 1.2 0 1 1 1.697 1.697l-2.758 3.152 2.758 3.15a1.2 1.2 0 0 1 0 1.698z"/>
</svg>
</span>
<div className={`${props.isWarning ? "bg-yellow-100 border border-yellow-400 text-yellow-700" : "bg-red-100 border border-red-400 text-red-700"} px-4 py-3 mt-5 rounded-md relative flex justify-between items-center`} role="alert">
<span className={`${props.isWarning ? "" : "pr-7"} block sm:inline text-lg`} id="message">{props.message}</span>
{
!props.isWarning &&
<span className="absolute top-0 right-0 p-1 m-2" onClick={props.onClose}>
<svg className="text-red-500 fill-current h-6 w-6" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor"
d="M6.2253 4.81108C5.83477 4.42056 5.20161 4.42056 4.81108 4.81108C4.42056 5.20161 4.42056 5.83477 4.81108 6.2253L10.5858 12L4.81114 17.7747C4.42062 18.1652 4.42062 18.7984 4.81114 19.1889C5.20167 19.5794 5.83483 19.5794 6.22535 19.1889L12 13.4142L17.7747 19.1889C18.1652 19.5794 18.7984 19.5794 19.1889 19.1889C19.5794 18.7984 19.5794 18.1652 19.1889 17.7747L13.4142 12L19.189 6.2253C19.5795 5.83477 19.5795 5.20161 19.189 4.81108C18.7985 4.42056 18.1653 4.42056 17.7748 4.81108L12 10.5858L6.2253 4.81108Z" />
</svg>
</span>
}
</div>
)
}

31
components/Button.tsx Normal file
View File

@ -0,0 +1,31 @@
interface ButtonProps {
text?: string,
icon?: string,
loading?: boolean,
onClick: () => void,
}
function Button(props: ButtonProps): JSX.Element {
function handleTouchEnd(event: React.TouchEvent<HTMLButtonElement>) {
event.preventDefault();
event.stopPropagation();
props.onClick();
}
return (
<button
type="button"
onClick={props.onClick}
onTouchEnd={handleTouchEnd}
className="bg-gray-400 dark:bg-gray-600 hover:bg-gray-500 relative focus:outline-none h-20 text-white font-semibold rounded-md items-center flex justify-center">
{
props.icon && <img src={props.icon} className="w-12 h-12 mr-2 -ml-4" />
}
{props.text}
</button>
)
}
export default Button;

View File

@ -1,20 +1,16 @@
import {useTranslation} from 'next-i18next';
interface CheckProps {
text: string;
}
function Check(props: CheckProps): JSX.Element {
const { t } = useTranslation(["index"]);
return (
<li className="flex flex-row space-x-4 items-center">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mx-2 fill-current text-green-500" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
{props.text}
</li>
)
return (
<li className="flex flex-row space-x-4 items-center">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mx-2 fill-current text-green-500" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
{props.text}
</li>
)
}
export default Check;

View File

@ -13,6 +13,7 @@ import {getPayloadBodyFromFile, getPayloadBodyFromQR} from "../src/process";
import {PassData} from "../src/pass";
import {COLORS} from "../src/colors";
import Colors from './Colors';
import Button from './Button';
function Form(): JSX.Element {
const {t} = useTranslation(['index', 'errors', 'common']);
@ -59,6 +60,44 @@ function Form(): JSX.Element {
});
}
}, [inputFile])
// Whether Safari is used or not
let [isSafari, setIsSafari] = useState<boolean>(true);
// Check if Safari is used
useEffect(() => {
const navigator = window.navigator;
setIsSafari(
navigator.vendor &&
navigator.vendor.indexOf('Apple') > -1 &&
navigator.userAgent &&
navigator.userAgent.indexOf('CriOS') == -1 &&
navigator.userAgent.indexOf('FxiOS') == -1
)
}, [isSafari]);
// Whether Safari is used or not
let [isShareDialogAvailable, setIsShareDialogAvailable] = useState<boolean>(false);
// Check if share dialog is available
useEffect(() => {
setIsShareDialogAvailable(window.navigator && window.navigator.share !== undefined);
}, [isShareDialogAvailable]);
// Open share dialog
async function showShareDialog() {
const shareData = {
title: document.title,
text: t('common:title') + ' ' + t('common:subtitle'),
url: window.location.protocol + "//" + window.location.host,
};
try {
await window.navigator.share(shareData);
} catch(error) {
console.log(error);
}
}
// Show file Dialog
async function showFileDialog() {
@ -102,7 +141,7 @@ function Form(): JSX.Element {
// Start decoding from video device
await codeReader.decodeFromVideoDevice(undefined,
previewElem,
(result, error, controls) => {
(result, _error, controls) => {
if (result !== undefined) {
setQrCode(result);
setFile(undefined);
@ -113,9 +152,6 @@ function Form(): JSX.Element {
setGlobalControls(undefined);
setIsCameraOpen(false);
}
if (error !== undefined) {
setErrorMessage(error.message);
}
}
)
);
@ -155,6 +191,9 @@ function Form(): JSX.Element {
const passBlob = new Blob([pass], {type: "application/vnd.apple.pkpass"});
saveAs(passBlob, 'covid.pkpass');
setLoading(false);
var scrollingElement = (document.scrollingElement || document.body);
scrollingElement.scrollTop = scrollingElement.scrollHeight;
} catch (e) {
setErrorMessage(e.message);
setLoading(false);
@ -164,22 +203,15 @@ function Form(): JSX.Element {
return (
<div>
<form className="space-y-5" id="form" onSubmit={addToWallet}>
{
!isSafari && <Alert isWarning={true} message={t('iosHint')} onClose={() => {}}/>
}
<Card step="1" heading={t('index:selectCertificate')} content={
<div className="space-y-5">
<p>{t('index:selectCertificateDescription')}</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
<button
type="button"
onClick={isCameraOpen ? hideCameraView : showCameraView}
className="focus:outline-none h-20 bg-gray-500 hover:bg-gray-700 text-white font-semibold rounded-md">
{isCameraOpen ? t('index:stopCamera') : t('index:startCamera')}
</button>
<button
type="button"
onClick={showFileDialog}
className="focus:outline-none h-20 bg-gray-500 hover:bg-gray-700 text-white font-semibold rounded-md">
{t('index:openFile')}
</button>
<Button text={isCameraOpen ? t('index:stopCamera') : t('index:startCamera')} onClick={isCameraOpen ? hideCameraView : showCameraView} />
<Button text={t('index:openFile')} onClick={showFileDialog} />
</div>
<video id="cameraPreview"
@ -195,7 +227,7 @@ function Form(): JSX.Element {
<div className="flex items-center space-x-1">
<svg className="h-4 w-4 text-green-600" fill="none" viewBox="0 0 24 24"
stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5l7 7-7 7"/>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="3" d="M9 5l7 7-7 7"/>
</svg>
<span className="w-full truncate">
{
@ -245,27 +277,38 @@ function Form(): JSX.Element {
</Link>.
</p>
</label>
<div className="flex flex-row items-center justify-start">
<button id="download" type="submit"
className="focus:outline-none bg-green-600 py-2 px-3 text-white font-semibold rounded-md disabled:bg-gray-400">
<div className="grid grid-cols-1">
<button
type="submit"
className="bg-green-600 hover:bg-green-700 relative focus:outline-none h-20 text-white font-semibold rounded-md items-center flex justify-center">
<div id="spin" className={`${loading ? undefined : "hidden"} absolute left-2`}>
<svg className="animate-spin h-5 w-5 ml-4" viewBox="0 0 24 24">
<circle className="opacity-0" cx="12" cy="12" r="10" stroke="currentColor"
strokeWidth="4"/>
<path className="opacity-80" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/>
</svg>
</div>
{t('index:addToWallet')}
</button>
<div id="spin" className={loading ? undefined : "hidden"}>
<svg className="animate-spin h-5 w-5 ml-4" viewBox="0 0 24 24">
<circle className="opacity-0" cx="12" cy="12" r="10" stroke="currentColor"
strokeWidth="4"/>
<path className="opacity-75" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"/>
</svg>
</div>
</div>
</div>
}/>
{
errorMessage && <Alert isWarning={false} message={errorMessage} onClose={() => setErrorMessage(undefined)}/>
}
<Card content={
<div className={`${isShareDialogAvailable ? "md:grid-cols-2": ""} grid-cols-1 grid gap-5`}>
{
isShareDialogAvailable && <Button text={t('index:share')} onClick={showShareDialog} />
}
<Button icon="kofi.png" text={t('common:donate')} onClick={() => {
window.open('https://ko-fi.com/marvinsxtr', '_blank');
}} />
</div>
}/>
</form>
<canvas id="canvas" style={{display: "none"}}/>
{
errorMessage && <Alert errorMessage={errorMessage} onClose={() => setErrorMessage(undefined)}/>
}
</div>
)
}

View File

@ -12,7 +12,7 @@ function Page(props: PageProps): JSX.Element {
const { t } = useTranslation('common');
return (
<div className="md:w-2/3 xl:w-2/5 md:mx-auto flex flex-col min-h-screen justify-center px-5 py-12">
<div className="md:w-2/3 xl:w-2/5 md:mx-auto flex flex-col min-h-screen justify-center px-5 pt-12 pb-16">
<Head>
<title>{t('common:title')}</title>
<link rel="icon" href="/favicon.ico"/>
@ -24,8 +24,7 @@ function Page(props: PageProps): JSX.Element {
{props.content}
<footer>
<nav className="nav flex pt-4 flex-row space-x-4 justify-center text-md font-bold flex-wrap">
<a href="https://ko-fi.com/marvinsxtr" className="hover:underline">{t('common:donate')}</a>
<nav className="nav flex flex-row space-x-4 justify-center text-md font-bold flex-wrap">
<a href="https://github.com/marvinsxtr/covidpass" className="hover:underline">{t('common:gitHub')}</a>
<Link href="/privacy"><a className="hover:underline">{t('common:privacyPolicy')}</a></Link>
<Link href="/imprint"><a className="hover:underline">{t('common:imprint')}</a></Link>

1
next-env.d.ts vendored
View File

@ -1,5 +1,4 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited

View File

@ -11,7 +11,9 @@ module.exports = {
'it', 'it-IT', 'it-CH',
'es', 'es-ES',
'no', 'no-NO',
'nb', 'nb-NO'
'nb', 'nb-NO',
'sv', 'sv-SE', 'sv-FI',
'ro', 'ro-RO', 'ro-MD'
],
localeExtension: 'yml',
},

View File

@ -2,4 +2,12 @@ const {i18n} = require('./next-i18next.config');
module.exports = {
i18n,
async rewrites() {
return [
{
source: '/pass/note',
destination: '/pass'
}
];
}
};

View File

@ -10,30 +10,32 @@
},
"dependencies": {
"@headlessui/react": "^1.3.0",
"@zxing/browser": "^0.0.9",
"@zxing/library": "^0.18.6",
"@zxing/browser": "^0.1.1",
"@zxing/library": "^0.19.1",
"base45": "^3.0.0",
"cbor-js": "^0.1.0",
"do-not-zip": "^1.0.0",
"file-saver": "^2.0.5",
"jsqr": "^1.4.0",
"next": "12",
"next-i18next": "^8.5.1",
"next-seo": "^4.26.0",
"node-fetch": "^2.6.1",
"next": "^12.1.5",
"next-i18next": "^11.0.0",
"next-seo": "^5.4.0",
"node-fetch": "^3.2.3",
"pako": "^2.0.4",
"pdfjs-dist": "^2.5.207",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-qr-code": "^2.0.3",
"uuid": "^8.3.2",
"webpack": "^5.0.0",
"worker-loader": "^3.0.7"
},
"devDependencies": {
"@types/pako": "^1.0.1",
"@types/react": "^17.0.11",
"@types/react": "^18.0.5",
"autoprefixer": "^10.0.4",
"postcss": "^8.1.10",
"tailwindcss": "^2.1.1",
"tailwindcss": "^3.0.24",
"typescript": "^4.3.4"
}
}

View File

@ -14,12 +14,12 @@ function Imprint(): JSX.Element {
<p className="font-bold">{t('imprint:heading')}</p>
<p>
Marvin Sextro<br />
Wilhelm-Busch-Str. 8A<br />
30167 Hannover<br />
Kopenhagener Straße 45<br />
10437 Berlin
</p>
<p className="font-bold">{t('imprint:contact')}</p>
<p>
<a href="mailto:marvin.sextro@gmail.com" className="underline">marvin.sextro@gmail.com</a>
<a href="mailto:covidpass@marvinsextro.de" className="underline">covidpass@marvinsextro.de</a>
</p>
<p className="font-bold">{t('imprint:euDisputeResolution')}</p>
<p>{t('imprint:euDisputeResolutionParagraph')}</p>

View File

@ -40,9 +40,8 @@ function Index(): JSX.Element {
<Page content={
<div className="space-y-5">
<Card content={
<p>{t('common:subtitle')}&nbsp;{t('index:iosHint')}</p>
<p>{t('common:subtitle')}</p>
}/>
<Form/>
</div>
}/>

66
pages/pass.tsx Normal file
View File

@ -0,0 +1,66 @@
import {useTranslation} from 'next-i18next';
import {serverSideTranslations} from 'next-i18next/serverSideTranslations';
import React, {useEffect, useState} from "react";
import QRCode from "react-qr-code";
import Alert from '../components/Alert';
import Card from '../components/Card';
import Logo from "../components/Logo";
function Pass(): JSX.Element {
const { t } = useTranslation(['common', 'index']);
const [fragment, setFragment] = useState<string>(undefined);
const [view, setView] = useState<boolean>(true);
useEffect(() => {
const rawFragment = window.location.hash.substring(1);
if (!rawFragment) {
setView(false);
}
const resizeTimeout = window.setTimeout(() => {
if (rawFragment) {
window.location.replace('/pass/note');
}
}, 200);
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
const decodedFragment = Buffer.from(rawFragment, 'base64').toString();
setFragment(decodedFragment);
});
}, []);
return (
<div className="py-5 flex flex-col space-y-5 md:w-2/3 xl:w-2/5 md:mx-auto items-center justify-center px-5">
<Logo/>
<div className="flex flex-row items-center">
{
fragment &&
<Card content={
<div className="p-2 bg-white rounded-md">
<QRCode value={fragment} size={280} level="L" />
</div>
} />
}
{
!view &&
<Alert isWarning={true} message={t('index:viewerNote')} onClose={undefined} />
}
</div>
</div>
)
}
export async function getStaticProps({ locale }) {
return {
props: {
...(await serverSideTranslations(locale, ['index', 'common'])),
},
};
}
export default Pass;

View File

@ -49,12 +49,11 @@ function Privacy(): JSX.Element {
</div>
<p className="font-bold">{t('privacy:contact')}</p>
<p>
Marvin Sextro<br/>
Wilhelm-Busch-Str. 8A<br/>
30167 Hannover<br/>
Marvin Sextro
<br/>
{t('privacy:email')}:
&nbsp;
<a href="mailto:marvin.sextro@gmail.com">marvin.sextro@gmail.com</a>
<a href="mailto:covidpass@marvinsextro.de" className="underline">covidpass@marvinsextro.de</a>
<br/>
{t('privacy:website')}:
&nbsp;
@ -137,9 +136,9 @@ function Privacy(): JSX.Element {
</a>
</li>
<li>
PayPal:
Ko-fi:
&nbsp;
<a href="https://www.paypal.com/de/webapps/mpp/ua/privacy-full?locale.x=en_EN" className="underline">
<a href="https://more.ko-fi.com/privacy" className="underline">
{t('common:privacyPolicy')}
</a>
</li>
@ -153,7 +152,7 @@ function Privacy(): JSX.Element {
<li>
{t('privacy:appleSync')}:
&nbsp;
<a href="https://www.apple.com/legal/privacy/en-ww/privacy.tsx" className="underline">
<a href="https://www.apple.com/legal/privacy/en-ww/" className="underline">
{t('common:privacyPolicy')}
</a>
</li>

BIN
public/kofi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,9 +1,7 @@
iosHint: Bitte verwende unter iOS den Safari Browser.
errorClose: Schließen
selectCertificate: Zertifikat auswählen
selectCertificateDescription: |
Scanne den QR-Code auf Deinem Zertifikat oder wähle einen Screenshot oder eine PDF-Datei mit dem QR-Code.
Bitte beachte, dass die Auswahl einer Datei direkt von der Kamera nicht unterstützt wird.
selectCertificateDescription: Scanne den QR-Code auf Deinem Zertifikat oder wähle einen Screenshot oder eine PDF-Datei mit dem QR-Code.
stopCamera: Kamera stoppen
startCamera: Kamera starten
openFile: Datei auswählen
@ -26,4 +24,6 @@ iAcceptThe: Ich akzeptiere die
privacyPolicy: Datenschutzerklärung
createdOnDevice: Auf Deinem Gerät erstellt
openSourceTransparent: Open Source und transparent
hostedInEU: In der EU gehostet
hostedInEU: In der EU gehostet
share: Weiterempfehlen
viewerNote: Bitte drücke und halte den Link auf der Rückseite des Passes, um den QR Code unter iOS vergrößert anzuzeigen.

View File

@ -1,9 +1,7 @@
iosHint: Στο iOS, παρακαλώ χρησιμοποιήστε τον περιηγητή Safari.
errorClose: Κλείσιμο
selectCertificate: Επιλογή Πιστοποιητικού
selectCertificateDescription: |
Παρακαλώ σαρώστε τον κωδικό QR του πιστοποιητικού σας ή επιλέξτε ένα στιγμιότυπο οθόνης ή την σελίδα PDF με τον κωδικό QR.
Λάβετε υπόψη πως η απευθείας επιλογή κάποιου αρχείου μέσω της κάμερας, δεν υποστηρίζεται.
selectCertificateDescription: Παρακαλώ σαρώστε τον κωδικό QR του πιστοποιητικού σας ή επιλέξτε ένα στιγμιότυπο οθόνης ή την σελίδα PDF με τον κωδικό QR.
stopCamera: Τερματισμός Κάμερας
startCamera: Εκκίνηση Κάμερας
openFile: Επιλογή Αρχείου
@ -27,3 +25,4 @@ privacyPolicy: Πολιτική Απορρήτου
createdOnDevice: Δημιουργείται στη συσκευή σας
openSourceTransparent: Ανοιχτού κώδικα και διαφανής
hostedInEU: Φιλοξενείται στην ΕΕ
share: Κοινοποιήστε το

View File

@ -1,9 +1,7 @@
iosHint: On iOS, please use the Safari Browser.
errorClose: Close
selectCertificate: Select Certificate
selectCertificateDescription: |
Please scan the QR code on your certificate or select a screenshot or PDF page with the QR code.
Note that selecting a file directly from camera is not supported.
selectCertificateDescription: Please scan the QR code on your certificate or select a screenshot or PDF page with the QR code.
stopCamera: Stop Camera
startCamera: Start Camera
openFile: Select File
@ -26,4 +24,6 @@ iAcceptThe: I accept the
privacyPolicy: Privacy Policy
createdOnDevice: Created on your device
openSourceTransparent: Open source and transparent
hostedInEU: Hosted in the EU
hostedInEU: Hosted in the EU
share: Share
viewerNote: Please press and hold the link on the back of the pass in order to enlarge the QR code on iOS.

View File

@ -1,9 +1,7 @@
iosHint: En iOS, Por favor use el navegador Safari.
errorClose: Cerrar
selectCertificate: Seleccione Certificado
selectCertificateDescription: |
Escanee el código QR de su certificado, o seleccione una captura de pantalla o un PDF que contenga el código QR.
Tenga en cuenta que no se admite la selección de un archivo directamente desde la cámara.
selectCertificateDescription: Escanee el código QR de su certificado, o seleccione una captura de pantalla o un PDF que contenga el código QR.
stopCamera: Detener Cámara
startCamera: Iniciar Cámara
openFile: Seleccione archivo
@ -26,4 +24,5 @@ iAcceptThe: Acepto la
privacyPolicy: Política de Privacidad
createdOnDevice: Creado en su dispositivo
openSourceTransparent: Open source y transparente
hostedInEU: Alojado en la UE
hostedInEU: Alojado en la UE
share: Recomendar

View File

@ -1,9 +1,7 @@
iosHint: Käytä iOS:ssä Safari-selainta.
errorClose: Sulje
selectCertificate: Valitse todistus
selectCertificateDescription: |
Skannaa todistuksessa oleva QR-koodi tai valitse kuvakaappaus tai PDF-sivu, jossa on QR-koodi.
Huomaa, että tiedoston valitsemista suoraan kamerasta ei tueta.
selectCertificateDescription: Skannaa todistuksessa oleva QR-koodi tai valitse kuvakaappaus tai PDF-sivu, jossa on QR-koodi.
stopCamera: Lopeta Kamera
startCamera: Käynnistä Kamera
openFile: Valitse Tiedosto
@ -26,4 +24,5 @@ iAcceptThe: Hyväksyn
privacyPolicy: Tietosuojaselosteen
createdOnDevice: Luotu laitteellasi
openSourceTransparent: Avoin lähdekoodi ja läpinäkyvä
hostedInEU: Isännöidään EU:ssa.
hostedInEU: Isännöidään EU:ssa.
share: Suosittele

View File

@ -1,9 +1,7 @@
iosHint: Sur iOS, veuillez utiliser le navigateur Safari.
errorClose: Fermez
selectCertificate: Sélectionner le certificat
selectCertificateDescription: |
Veuillez scanner le QR Code de votre certificat ou sélectionner une capture d'écran ou une page PDF avec le QR Code.
Notez que la sélection d'un fichier directement à partir de l'appareil photo n'est pas prise en charge.
selectCertificateDescription: Veuillez scanner le QR Code de votre certificat ou sélectionner une capture d'écran ou une page PDF avec le QR Code.
stopCamera: Arrêter l'appareil photo
startCamera: Démarrer l'appareil photo
openFile: Sélectionner un fichier
@ -26,4 +24,5 @@ iAcceptThe: J'accepte la
privacyPolicy: Politique de confidentialité
createdOnDevice : Créé sur votre appareil
openSourceTransparent : Open source et transparent
hostedInEU : Hébergé dans l'UE
hostedInEU : Hébergé dans l'UE
share: Recommander

View File

@ -1,9 +1,7 @@
iosHint: Su iOS, si prega di utilizzare il browser Safari.
errorClose: Chiudi
selectCertificate: Seleziona il certificato
selectCertificateDescription: |
Scannerizza il codice QR sul tuo certificato o seleziona uno screenshot o una pagina PDF con il codice QR.
Nota che la selezione di un file direttamente dalla fotocamera non è supportata.
selectCertificateDescription: Scannerizza il codice QR sul tuo certificato o seleziona uno screenshot o una pagina PDF con il codice QR.
stopCamera: Blocca Fotocamera
startCamera: Avvia Fotocamera
openFile: Seleziona un File
@ -27,3 +25,4 @@ privacyPolicy: Privacy Policy
createdOnDevice: Creato sul tuo dispositivo
openSourceTransparent: Open source e trasparente
hostedInEU: Server nell'UE
share: Raccomandare

View File

@ -1,9 +1,7 @@
iosHint: På iOS, vennligst bruk Safari nettleseren.
errorClose: Lukk
selectCertificate: Velg Sertifikat
selectCertificateDescription: |
Skann QR-koden på sertifikatet ditt, eller velg et skjermbilde eller en PDF med QR-koden.
Vær oppmerksom på at det ikke støttes å velge en fil direkte fra kameraet.
selectCertificateDescription: Skann QR-koden på sertifikatet ditt, eller velg et skjermbilde eller en PDF med QR-koden.
stopCamera: Stopp Kamera
startCamera: Start Kamera
openFile: Velg Fil
@ -27,3 +25,4 @@ privacyPolicy: Personvernerklæring
createdOnDevice: Laget på enheten din
openSourceTransparent: Åpen kildekode og gjennomsiktig
hostedInEU: Driftet i EU
share: Anbefale

View File

@ -1,9 +1,7 @@
iosHint: Gebruik op iOS de Safari-browser.
errorClose: Sluiten
selectCertificate: Selecteer Certificaat
selectCertificateDescription: |
Scan de QR-code op uw certificaat of selecteer een screenshot of pdf-pagina met de QR-code.
Merk op dat het rechtstreeks vanaf de camera selecteren van een bestand niet wordt ondersteund.
selectCertificateDescription: Scan de QR-code op uw certificaat of selecteer een screenshot of pdf-pagina met de QR-code.
stopCamera: Stop Camera
startCamera: Start Camera
openFile: Selecteer Bestand
@ -26,4 +24,5 @@ iAcceptThe: Ik accepteer het
privacyPolicy: Privacybeleid
createdOnDevice: Aangemaakt op uw apparaat
openSourceTransparent: Open source en transparant
hostedInEU: Gehost in de EU
hostedInEU: Gehost in de EU
share: Aanbevelen

1
public/locales/ro-MD Symbolic link
View File

@ -0,0 +1 @@
ro

1
public/locales/ro-RO Symbolic link
View File

@ -0,0 +1 @@
ro

View File

@ -0,0 +1,6 @@
title: CovidPass
subtitle: Adaugă-ți Certificatul UE Covid in aplicația ta preferată de wallet.
privacyPolicy: Politica de Confidențialitate
donate: Donează
gitHub: GitHub
imprint: Mențiuni Legale

View File

@ -0,0 +1,20 @@
noFileOrQrCode: Te rog scaneaza un cod QR, sau alege un fisier
signatureFailed: Eroare in timpul semnarii certificatului pe server
decodingFailed: Imposibil de decodat continutul codului QR
invalidColor: Culoare Invalida
certificateData: Eroare in citirea datelor certificatului
nameMissing: Eroare in citirea numelui
dobMissing: Eroare in citirea datei de nastere
invalidMedicalProduct: Produs medical (Vaccin) invalid
invalidCountryCode: Codul tarii este invalid
invalidManufacturer: Fabricant invalid
invalidFileType: Tipul fisierului invalid
couldNotDecode: Eroare in decodarea codului QR din fisier
couldNotFindQrCode: Nu s-a gasit niciun cod QR valid in fisierul selectat
invalidQrCode: Cod QR invalid
certificateType: Tipul certificatului este invalid
invalidTestResult: Rezultatul testului este invalid
invalidTestType: Tipul testului este invalid
noCameraAccess: Nu s-a putut accesa camera. Schimbati permisiunile in Setari > Safari > Camera.
noCameraFound: Nu s-a putut accesa camera.
safariSupportOnly: in iOS, va rog sa folositi doar browser-ul safari.

View File

@ -0,0 +1,27 @@
heading: Informații conform articolului 5 TMG
contact: Contact
euDisputeResolution: Soluționarea Disputelor UE
euDisputeResolutionParagraph: |
Comisia Europeana dispune de o platforma pentru soluționarea disputelor online (OS) https://ec.europa.eu/consumers/odr.
Ne puteți găsi adresa de email in datele de mai sus.
consumerDisputeResolution: Rezolvarea litigiilor consumatorilor / comisia universală de arbitraj
consumerDisputeResolutionParagraph: Nu suntem dispuși sau obligați să participăm la procedurile de soluționare a litigiilor în fața unei comisii de arbitraj pentru consumatori.
liabilityForContents: Raspunderea pentru continut
liabilityForContentsParagraph: |
În calitate de furnizori de servicii, suntem responsabili pentru conținutul propriu în conformitate cu articolul 7 paragraful 1 TMG în conformitate cu legile generale.
Conform secțiunilor 8 până la 10, nu suntem obligați să monitorizăm informațiile transmise sau stocate sau să investigăm circumstanțe care indică o activitate ilegală.
Obligațiile de a elimina sau de a bloca utilizarea informațiilor conform legilor generale rămân neafectate.
Cu toate acestea, răspunderea în această privința este posibilă numai din momentul în care devine cunoscută o încălcare concretă a legii.
Dacă aflăm de existența unor asemenea încălcări, vom elimina imediat conținutul relevant.
liabilityForLinks: Raspunderea pentru linkuri
liabilityForLinksParagraph: |
Oferta noastră conține link-uri către site-uri externe ale terților, asupra cărora nu avem nicio influență.
Prin urmare, nu ne putem asuma nicio răspundere pentru aceste conținuturi externe.
Furnizorul sau operatorul respectiv al site-urilor este întotdeauna responsabil pentru conținutul site-urilor mentionate.
Paginile conectate au fost verificate pentru posibile încălcări legale la momentul punerii link-ului.
Conținuturile ilegale nu erau recunoscute în momentul punerii link-urilor.
Cu toate acestea, un control permanent al conținutului paginilor linkate nu este rezonabil fără dovezi concrete ale unei încălcări a legii.
Dacă aflăm că există încălcări, vom elimina imediat astfel de legături.
credits: Credite
creditsSource: Cu extrase din https://www.e-recht24.de/impressum-generator.html
creditsTranslation: Tradus cu https://www.DeepL.com/Translator (free version)

View File

@ -0,0 +1,28 @@
iosHint: In iOS, te rog foloseste browser-ul Safari.
errorClose: Inchide
selectCertificate: Alege certificatul
selectCertificateDescription: Te rog scaneaza codul QR de pe certificatul tau sau alege un screenshot/PDF cu codul QR
stopCamera: Opreste Camera
startCamera: Porneste Camera
openFile: Selecteaza fisierul
foundQrCode: Cod QR detectat!
pickColor: Alege o culoare
pickColorDescription: Alege o culoare de fundal pentru certificatul tau.
colorWhite: alb
colorBlack: negru
colorGrey: gri
colorGreen: verde
colorIndigo: indigo
colorBlue: albastru
colorPurple: mov
colorTeal: teal
addToWallet: Adauga in Wallet
dataPrivacyDescription: |
Confidentialitatea datelor este de o importanta speciala cand vine vorba de date medicale.
Pentru a face o alegere informata, va rugam cititi
iAcceptThe: Sunt de acord cu
privacyPolicy: Politica de Confidentialitate
createdOnDevice: Creat pe dispozitivul tau
openSourceTransparent: Open source si transparent
hostedInEU: Gazduit in UE
share: Distribuie

View File

@ -0,0 +1,57 @@
gdprNotice: |
Politica noastră de confidențialitate se bazează pe termenii folosiți de legiuitorul european
pentru adoptarea Regulamentului general privind protecția datelor (GDPR).
generalInfo: Informații Generale
generalInfoProcess: |
Întregul proces de generare a fișierului de Wallet are loc local în browserul dvs.
Pentru pasul de semnare (certificare), doar o reprezentare hashed (codata ireversibil) a datelor dvs. este trimisă către server.
generalInfoStoring: Datele dumneavoastră nu sunt stocate dincolo de sesiunea activă a browserului, iar site-ul nu utilizează cookie-uri.
generalInfoThirdParties: Nu sunt trimise date catre părți terțe.
generalInfoHttps: Datele sunt transmise în mod securizat prin https.
generalInfoLocation: Serverele noastre sunt găzduite in Nuremberg, Germania.
generalInfoGitHub: Codul sursă al acestui site este accesibil pe
generalInfoLockScreen: În mod normal, cardurile din Apple Wallet sunt accesibile de pe lock screen. Puteți schimba acest lucru in
settings: setări
generalInfoProvider: |
Furnizorul de server prelucrează date pentru a furniza acest site.
Pentru a înțelege mai bine ce măsuri iau aceștia pentru a vă proteja datele, vă rugăm să citiți și pe partea lor
privacyPolicy: Politica de Confidențialitate
andThe: și
dataPrivacyFaq: Întrebari puse des despre confidențialitate
contact: Contact
email: Email
website: Website
process: Explicație simplificata a procesului
processFirst: În primul rând, următorii pași au loc local în browserul dvs
processSecond: În al doilea rând, următorii pași au loc pe serverul nostru
processThird: În cele din urmă, următorii pași au loc local în browserul dvs
processRecognizing: Recunoașterea și extragerea datelor codului QR din certificatul selectat
processDecoding: Decodificarea datelor dvs. personale și medicale din încărcarea codului QR
processAssembling: Asamblarea unui fișier de Wallet incomplet din datele dvs
processGenerating: Generarea unui fișier care conține hash-uri ale datelor stocate în fișierul wallet
processSending: Trimiterea doar fișierul care conține hash-urile către serverul nostru
processReceiving: Primirea și verificarea hashurilor care au fost generate local
processSigning: Semnarea fișierului care conține hashurile
processSendingBack: Trimiterea semnăturii înapoi
processCompleting: Asamblarea fișierului wallet semnat din fișierul incomplet generat local și semnătura
processSaving: Salvarea fisierului pe dispozitiv
locallyProcessedData: Date procesate local
the:
schema: Schema Certificatului Digital Covid
specification: contine o schema complete cu datele care sunt continute de codul QR al certificatului covid si care vor fi procesate in browser.
serverProvider: Furnizorul de Servere
serverProviderIs: Furnizorul nostru de servere este
logFiles: Următoarele date pot fi colectate și stocate în fișierele jurnal ale serverului
logFilesBrowser: Tipurile și versiunile de browser utilizate
logFilesOs: Sistemul de operare utilizat de sistemul de accesare
logFilesReferrer: Site-ul web de pe care un sistem de accesare ajunge pe site-ul nostru web (așa-numiții recomandanți)
logFilesTime: Data și ora accesului
logFilesIpAddress: Adresele IP pseudonimizate
rights: Drepturile tale
rightsGranted: În conformitate cu GDPR, aveți următoarele drepturi
rightsAccess: Dreptul de acces la datele dumneavoastră; Ai dreptul să știi ce date au fost colectate despre tine și cum au fost prelucrate.
rightsErasure: Dreptul de a fi uitat; Ștergerea datelor dumneavoastră personale.
rightsRectification: Dreptul de rectificare; Aveți dreptul de a corecta datele eronate.
rightsPortability: Dreptul la portabilitatea datelor; Aveți dreptul să vă transferați datele dintr-un sistem de procesare în altul.
thirdParties: Părți terțe
appleSync: Este posibil ca Apple să vă sincronizeze cardurile wallet prin iCloud

1
public/locales/sv-FI Symbolic link
View File

@ -0,0 +1 @@
sv

1
public/locales/sv-SE Symbolic link
View File

@ -0,0 +1 @@
sv

View File

@ -0,0 +1,6 @@
title: CovidPass
subtitle: Lägg till digitala Covid-certifikat från EU i din favorit plånboks app.
privacyPolicy: Integritetspolicy
donate: Sponsra
gitHub: GitHub
imprint: Juridisk info

View File

@ -0,0 +1,20 @@
noFileOrQrCode: Vänligen skanna en QR-kod eller välj en fil
signatureFailed: Fel vid pass-signering på server
decodingFailed: Misslyckades att avkoda QR-kodens nyttolast
invalidColor: Ogiltig färg
certificateData: Misslyckades att läsa in certifikatdata
nameMissing: Inläsning av namn misslyckades
dobMissing: Inläsning av födelsedatum misslyckades
invalidMedicalProduct: Ogiltig medicinsk produkt
invalidCountryCode: Ogiltig landskod
invalidManufacturer: Ogiltig tillverkare
invalidFileType: Ogiltig filtyp
couldNotDecode: Kunde inte avkoda QR-kod från fil
couldNotFindQrCode: Kunde inte hitta QR-kod i försedd fil
invalidQrCode: Ogiltig QR-kod
certificateType: Ingen giltig certifikatstyp hittades
invalidTestResult: Ogiltigt testreultat
invalidTestType: Ogiltig testtyp
noCameraAccess: Nekades tillgång till kamera. Kontrollera behörigheter under Inställningar > Safari > Kamera.
noCameraFound: Kunde inte hitta kamera.
safariSupportOnly: På iOS, vänligen använd Safari som webbläsare.

View File

@ -0,0 +1,26 @@
heading: Information i enlighet med § 5 Tyska telemedielagen (TMG)
contact: Kontakt
euDisputeResolution: Tvistlösning inom EU
euDisputeResolutionParagraph: |
Europeiska kommissionen tillhandahåller en plattform för tvistlösning online via https://ec.europa.eu/consumers/odr.
Du hittar vår e-postadress i stycket ovan.
consumerDisputeResolution: Konsumenttvistlösning / Allmän sklijenämnd
consumerDisputeResolutionParagraph: Vi är inte villiga eller ålagda att delta i tvistlösningsärenden inför en konsumentskiljenämnd.
liabilityForContents: Ansvar för innehåll
liabilityForContentsParagraph: |
Som tjänsteleverantör är vi ansvariga för vårt eget innehåll på dessa sidor i enlighet med § 7 paragraf 1 TMG under de almänna lagarna.
Enligt §§ 8 till 10 TMG är vi inte skyldiga att övervaka överförd eller lagrad information eller undersöka omständligheter som påvisar olaglig verksamhet.
Skyldigheter att radera eller blockera användande av information under de allmänna lagarna förblir opåverkade.
Dock är ansvar i detta avseende endast möjligt från den tidpunkt en konkret överträdelse av lagen blir känd. Om vi blir medvetna om en sådan överträdelse kommer vi obedelbart ta bort den information som är relevant i sammanhanget.
liabilityForLinks: Ansvar för länkar
liabilityForLinksParagraph: |
Vårt erbjudande innehåller länkar till tredjeparters externa webbplatser, vars innehåll vi inte har inflytande över.
Vi kan därför inte åta oss något ansvar för dessa externa innehåll.
Leverantören eller operatören för respektive länkad webbplats är alltid ansvariga för dess respektive innehåll.
De länkade sidorna kontrollerades för eventuella lagliga överträdelser vid den tidpunkt de länkades.
Inget olagligt innehåll kunde påvisas vid tidpunkten för länkning.
Permanenta kontroller av de länkade webbplatsernas innehåll är dock inte rimliga utan konkreta bevis för lagbrott.
Om vi blir medvetna om några överträdelser kommer vi omedelbart radera länkarna ifråga.
credits: Erkännanden
creditsSource: Med utdrag från https://www.e-recht24.de/impressum-generator.html
creditsTranslation: Översatt med https://www.DeepL.com/Translator (gratis version)

View File

@ -0,0 +1,28 @@
iosHint: På iOS, vänligen använd Safari som webbläsare.
errorClose: Stäng
selectCertificate: Välj certifikat
selectCertificateDescription: Vänligen skanna QR-koden på ditt certifikat eller välj en skärmdump eller PDF-fil som innehåller QR-koden.
stopCamera: Stäng kamera
startCamera: Öppna kamera
openFile: Välj fil
foundQrCode: QR-kod hittad!
pickColor: Välj en färg
pickColorDescription: Välj en bakgrundsfärg till ditt pass.
colorWhite: vit
colorBlack: svart
colorGrey: grå
colorGreen: grön
colorIndigo: indigo
colorBlue: blå
colorPurple: lila
colorTeal: turkos
addToWallet: Lägg till i Plånbok
dataPrivacyDescription: |
Datasekretess är av särskild vikt vid bearbetning av hälsorelaterad data.
För att du ska kunna fatta ett välgrundat beslut, vänligen läs
iAcceptThe: Jag godtar
privacyPolicy: integritetspolicyn
createdOnDevice: Skapad på din enhet
openSourceTransparent: Öppen källkod och transparent
hostedInEU: Drivs från EU
share: Rekommendera

View File

@ -0,0 +1,56 @@
gdprNotice: |
Vår integritetspolicy är baserad på de villkår som används av den europeiska lagstiftaren för verkställandet av den allmänna dataskyddsförordningen (GDPR).
generalInfo: Allmän information
generalInfoProcess: |
Hela den process som genererar passfilen sker lokalt i din webbläsare.
Under signeringen skickas endast en kondenserad motsvarighet av din data till servern.
generalInfoStoring: Din data sparas inte utanför den aktiva webbläsar sessionen och sidan använder sig inte av cookies.
generalInfoThirdParties: Ingen data skickas till tredjeparter.
generalInfoHttps: Vi överför din data säkert över HTTPS.
generalInfoLocation: Vår server är baserad i Nürnberg, Tyskland.
generalInfoGitHub: Källkoden till denna sida finns tillgänglig på
generalInfoLockScreen: Som standrad är kuponger i Apple Plånbok tillgängliga från låsskärmen. Detta kan ändras i
settings: Inställningar
generalInfoProvider: |
Tjänsteleverantören processerar data som sedan används av sidan.
För att bättre förstå vilka åtgärder de vidtar för att skydda din data, vänligen läs deras
privacyPolicy: integritetspolicy
andThe: samt deras
dataPrivacyFaq: FAQ om datasekretess
contact: Kontakt
email: E-post
website: Hemsida
process: Förenklad förklaring av processen
processFirst: Först genomförs följande steg lokalt i din webbläsare
processSecond: Sedan genomförs följande steg på vår server
processThird: Slutligen genomförs följande steg lokalt i din webbläsare
processRecognizing: Datan från QR-koden i ditt valda certifikat identifieras och extraheras
processDecoding: Din personliga hälsorelaterade data från QR-kodens nyttolast avkodas
processAssembling: En ofullständig passfil sätts ihop genom din data
processGenerating: En fil med kondenseringar av den data som finns lagrad i passfilen genereras
processSending: Endast den fil som innehåller kondenseringarna skickas till vår server
processReceiving: De kondenseringar som genererades lokalt tas emot och kontrolleras
processSigning: Filen som innehåller kondenseringarna signeras
processSendingBack: Signaturen skickas tillbaka
processCompleting: En signerad passfil sätts ihop genom signaturen samt den ofullständiga, lokalt genererade filen
processSaving: Filen sparas på din enhet
locallyProcessedData: Lokalt behandlad data
the:
schema: Digital Covid Certificate Schema
specification: innehåller en detaljerad specifikation av den data som finns i QR-koden och som kommer att bearbetas i din webbläsare.
serverProvider: Serverleverantör
serverProviderIs: Vår serverleverantör är
logFiles: Följande data kan komma att samlas in och sparas i serverns loggfiler.
logFilesBrowser: Webbläsartyper och versioner
logFilesOs: Operativsystemet som används av den klient som begär tillgång
logFilesReferrer: Den webbsida från vilken den klient som begärt tillgång har nått vår webbsida (så kallade hänvisare)
logFilesTime: Datum och tid för tillgång
logFilesIpAddress: Den pseudonymiserade IP-adressen
rights: Dina rättigheter
rightsGranted: I enlighet med GDPR har du följande rättigheter
rightsAccess: Rätt till åtkomst av din data; Du har rätt att få veta vilken data som som har samlats in om dig samt hur den har bearbetats.
rightsErasure: Rätten att bli bortglömd; Du har rätt till att få din personliga data raderad.
rightsRectification: Rätt att göra invändningar; Du har rätt till att korrigera felaktiga data.
rightsPortability: Rätt till dataportabilitet; Du har rätt till överförning av din data från ett bearbetningssystem till ett annat.
thirdParties: Länkar till tredjeparter
appleSync: Apple kan komma att synkronisera dina pass via iCloud

3
public/robots.txt Normal file
View File

@ -0,0 +1,3 @@
User-agent: *
Disallow: /pass
Disallow: /pass/note

View File

@ -20,6 +20,10 @@ export function typedArrayToBuffer(array: Uint8Array): ArrayBuffer {
}
export function decodeData(data: string): Object {
if (data.startsWith('https://')) {
var url = new URL(data);
data = decodeURIComponent(url.hash.substring(1));
}
if (data.startsWith('HC1')) {
data = data.substring(3);
@ -45,4 +49,4 @@ export function decodeData(data: string): Object {
var decoded: Object = cbor.decode(typedArrayToBufferSliced(plaintext));
return decoded;
}
}

View File

@ -19,6 +19,7 @@ interface QrCode {
message: string;
format: QrFormat;
messageEncoding: Encoding;
altText: string;
}
interface SignData {
@ -83,6 +84,7 @@ export class PassData {
message: payload.rawData,
format: QrFormat.PKBarcodeFormatQR,
messageEncoding: Encoding.utf8,
altText: 'SCAN TO VERIFY',
}
// Create pass data

View File

@ -3,9 +3,9 @@ import {Constants} from "./constants";
import {COLORS} from "./colors";
enum CertificateType {
Vaccination = 'Vaccination Card',
Test = 'Test Certificate',
Recovery = 'Recovery Certificate',
Vaccination = 'Vaccination Pass',
Test = 'Test Pass',
Recovery = 'Recovery Pass',
}
enum TextAlignment {
@ -116,6 +116,11 @@ export class Payload {
const country = valueSets.countryCodes[countryCode].display;
// Encode raw data and get url
const encodedData = Buffer.from(body.rawData).toString('base64');
const url = window.location.protocol + "//" + window.location.host;
const generic: PassDictionary = {
headerFields: [
{
@ -134,6 +139,11 @@ export class Payload {
secondaryFields: [],
auxiliaryFields: [],
backFields: [
{
key: "enlarge",
label: "Enlarging the QR Code",
value: `Inside the Wallet app on iOS, press and hold the link below. This does not work when accessing the Wallet by double-clicking the side button.\n<a href='${url}/pass#${encodedData}'>Enlarge QR Code</a>`
},
{
key: "uvci",
label: "Unique Certificate Identifier (UVCI)",
@ -157,10 +167,27 @@ export class Payload {
this.img2x = dark ? Constants.img2xWhite : Constants.img2xBlack
this.dark = dark;
this.generic = Payload.fillPassData(this.certificateType, generic, properties, valueSets, country, dateOfBirth);
this.generic = Payload.fillPassData(
this.certificateType,
generic,
properties,
valueSets,
country,
dateOfBirth,
url
);
}
static fillPassData(type: CertificateType, data: PassDictionary, properties: Object, valueSets: ValueSets, country: string, dateOfBirth: string): PassDictionary {
static fillPassData(
type: CertificateType,
data: PassDictionary,
properties: Object,
valueSets: ValueSets,
country: string,
dateOfBirth: string,
url: string
): PassDictionary {
switch (type) {
case CertificateType.Vaccination:
const dose = `${properties['dn']}/${properties['sd']}`;
@ -235,7 +262,17 @@ export class Payload {
throw new Error('invalidTestType')
}
const testResult = valueSets.testResults[testResultKey].display;
let testResult = valueSets.testResults[testResultKey].display;
switch (testResult) {
case 'Not detected':
testResult = 'Negative';
break;
case 'Detected':
testResult = 'Positive';
break;
}
const testType = valueSets.testTypes[testTypeKey].display;
const testTime = testDateTimeString.replace(/.*T/, '').replace('Z', ' ') + 'UTC';
@ -339,6 +376,14 @@ export class Payload {
throw new Error('certificateType');
}
data.backFields.push(...[
{
key: "credits",
label: "",
value: `Created with <a href='${url}'>CovidPass</a>`
}
]);
return data;
}
}

View File

@ -12,7 +12,6 @@ export async function getPayloadBodyFromFile(file: File, color: COLORS): Promise
switch (file.type) {
case 'application/pdf':
console.log('pdf')
// Read file
const fileBuffer = await file.arrayBuffer();
imageData = await getImageDataFromPdf(fileBuffer)
@ -21,7 +20,6 @@ export async function getPayloadBodyFromFile(file: File, color: COLORS): Promise
case 'image/jpeg':
case 'image/webp':
case 'image/gif':
console.log(`image ${file.type}`)
imageData = await getImageDataFromImage(file)
break
default:

2615
yarn.lock

File diff suppressed because it is too large Load Diff