Compare commits

..

48 Commits

Author SHA1 Message Date
100852fa66
Update name
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-26 12:40:14 +02:00
6513f2f08b
Change name 2020-07-23 21:25:00 +02:00
e3b7e75072
Change section order
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-22 19:05:15 +02:00
0554f432b1
Add correction 2020-07-22 17:05:21 +02:00
8fc33302e9
Add correction
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-21 11:42:37 +02:00
087a21eb07
Merge branch 'mqtt' into develop 2020-07-21 09:48:11 +02:00
3abdf776b0
Add network parameters 2020-07-21 09:47:40 +02:00
69ef5b620a
Add upload activity 2020-07-21 09:31:10 +02:00
f3ecfe46ff
Add UI 2020-07-19 12:48:41 +02:00
9949f60601
Update interface DAO
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-17 15:31:10 +02:00
ca5e20c7a0
Add publish code 2020-07-17 15:25:42 +02:00
0a28d778f2
Merge pull request #6 from Untori/mqtt
All checks were successful
continuous-integration/drone/push Build is passing
Mqtt
2020-07-16 19:04:51 +02:00
8648e99370 Add correction 2020-07-16 19:03:50 +02:00
27a912a997
Add mqtt 2020-07-16 16:57:21 +02:00
341d465642
Merge pull request #5 from Untori/api_ag
All checks were successful
continuous-integration/drone/push Build is passing
Add Apple Google api
2020-07-14 10:56:58 +02:00
b0e1e1684c
Add Apple Google api 2020-07-12 17:28:53 +02:00
c161830f6f
Merge branch 'tcn' into develop
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-10 18:11:30 +02:00
c7240fa790
Merge pull request #3 from Untori/bluetooth
Bluetooth
2020-07-10 17:35:54 +02:00
36e9b39e7f
Merge pull request #4 from Untori/room
Room
2020-07-10 17:35:36 +02:00
236da1e902 fixed key 2020-07-10 17:34:16 +02:00
f6bbded63a fixed report 2020-07-10 17:30:02 +02:00
d943975e3c
Add correction 2020-07-10 17:18:51 +02:00
676c873983
Add correction 2020-07-10 17:13:32 +02:00
8c684cbe62
Add some correction 2020-07-10 14:54:27 +02:00
d5ac71f2d6
Add DAO 2020-07-10 14:41:41 +02:00
58743a8bd5
Add memorizzazione 2020-07-10 12:48:24 +02:00
7d2720c952
Add bibliography 2020-07-10 12:26:40 +02:00
be84521a7b
Add BluetoothManager 2020-07-09 21:31:20 +02:00
bb7a3dc7ee
Fix note professor 2020-07-09 21:14:00 +02:00
9109738239 add reporting 2020-07-09 17:21:20 +02:00
b6ec9ec767
Add distance 2020-07-09 16:13:34 +02:00
660c79077a
Merge pull request #2 from Untori/tkn
All checks were successful
continuous-integration/drone/push Build is passing
Tkn
2020-07-09 15:57:00 +02:00
b772471a65
add library name 2020-07-09 15:56:16 +02:00
5d2e7c8c02
Add scanning 2020-07-09 15:52:43 +02:00
6e3df58d61
Merge pull request #1 from Untori/bluetooth
All checks were successful
continuous-integration/drone/push Build is passing
Bluetooth
2020-07-09 12:46:57 +02:00
d95e5ad382
Add correction 2020-07-09 12:45:13 +02:00
35190a2541
Add correction 2020-07-09 12:39:45 +02:00
d4fd16abee fixed tcn 2020-07-09 12:25:43 +02:00
7112ff839a
Add transition intensity 2020-07-08 21:40:27 +02:00
5de8b3b42b
Add transmission 2020-07-08 21:19:52 +02:00
98a13ea8a1 add tcn 2020-07-08 19:28:02 +02:00
fe3f3a31c6
Add app and bluetooth intro 2020-07-08 19:16:24 +02:00
f7e726ac7a
Add tck and report description 2020-07-08 15:55:32 +02:00
823dd6c9b6
Add pandoc-citeproc 2020-07-07 22:44:13 +02:00
ba7bd73b73
Add draft tkn 2020-07-07 22:32:23 +02:00
768d4377f9
Run CI only on master and develop
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-07 22:31:31 +02:00
b49ad291ad
Add documentation file
All checks were successful
continuous-integration/drone/push Build is passing
2020-07-06 22:31:34 +02:00
19f5d4d142
Add drone file
Some checks failed
continuous-integration/drone/push Build is failing
2020-07-06 22:29:35 +02:00
9 changed files with 1037 additions and 0 deletions

39
.drone.yml Normal file
View File

@ -0,0 +1,39 @@
kind: pipeline
type: docker
name: default
steps:
- name: compiling
image: norangebit/pandocker:latest
commands:
- make
- name: deploy
image: rclone/rclone:latest
commands:
- rclone copy out/*.pdf assd:Gruppo\ Progetto\ 1/documentazione
volumes:
- name: config
path: /config/rclone
- name: gitea release
image: plugins/gitea-release
settings:
api_key:
from_secret: gitea_release
base_url: https://git.norangeb.it
title: Documentazione Untori
files:
- out/*.pdf
when:
event:
- tag
trigger:
branch:
- master
- develop
volumes:
- name: config
host:
path: /home/drone/.config/rclone

128
bib.bib Normal file
View File

@ -0,0 +1,128 @@
@online{AdvertiseSettings,
title = {{{AdvertiseSettings}}},
journaltitle = {Android Developers},
url = {https://developer.android.com/reference/android/bluetooth/le/AdvertiseSettings?hl=it},
urldate = {2020-07-08},
file = {/home/norangebit/Zotero/storage/QA2E8KJT/AdvertiseSettings.html},
langid = {english}
}
@online{AdvicePublicCOVID19,
title = {Advice for the Public on {{COVID}}-19 \textendash{} {{World Health Organization}}},
url = {https://www.who.int/emergencies/diseases/novel-coronavirus-2019/advice-for-public},
urldate = {2020-07-08},
abstract = {Simple precautions to reduce your chances of being infected or spreading COVID-19.},
file = {/home/norangebit/Zotero/storage/ZY3MFYWP/advice-for-public.html},
langid = {english}
}
@online{AndroidBeaconLibrary,
title = {Android {{Beacon Library}}},
url = {https://altbeacon.github.io/android-beacon-library/},
urldate = {2020-07-08},
file = {/home/norangebit/Zotero/storage/RDCN2EQA/android-beacon-library.html}
}
@online{AndroidJetpackAndroid,
title = {Android {{Jetpack}} | {{Android Developers}}},
url = {https://developer.android.com/jetpack},
urldate = {2020-07-10},
abstract = {Jetpack is a suite of libraries to help developers follow best practices, reduce boilerplate code, and write code that works consistently across Android versions and devices so that developers can focus on the code they care about.},
file = {/home/norangebit/Zotero/storage/X2QST32B/jetpack.html},
langid = {english}
}
@online{AppleGooglePartner,
title = {Apple and {{Google}} Partner on {{COVID}}-19 Contact Tracing Technology},
journaltitle = {Apple Newsroom},
url = {https://www.apple.com/newsroom/2020/04/apple-and-google-partner-on-covid-19-contact-tracing-technology/},
urldate = {2020-07-12},
abstract = {Apple and Google announce a joint effort to help governments and health agencies reduce the spread of the virus, with user privacy central to the design.},
file = {/home/norangebit/Zotero/storage/V2SPLUEJ/apple-and-google-partner-on-covid-19-contact-tracing-technology.html},
langid = {american}
}
@online{BroadcastsOverview,
title = {Broadcasts Overview},
journaltitle = {Android Developers},
url = {https://developer.android.com/guide/components/broadcasts},
urldate = {2020-07-09},
file = {/home/norangebit/Zotero/storage/PVLZYLKD/broadcasts.html},
langid = {english}
}
@software{CryptographycafeEd25519elisabeth2020,
title = {Cryptography-Cafe/Ed25519-Elisabeth},
date = {2020-06-30T09:56:21Z},
origdate = {2019-03-17T03:50:16Z},
url = {https://github.com/cryptography-cafe/ed25519-elisabeth},
urldate = {2020-07-09},
abstract = {Pure Java implementation of Ed25519. Contribute to cryptography-cafe/ed25519-elisabeth development by creating an account on GitHub.},
keywords = {cryptography,ed25519,java,signature-scheme},
organization = {{cryptography-cafe}}
}
@online{EclipsePahoMQTT,
title = {Eclipse {{Paho}} - {{MQTT}} and {{MQTT}}-{{SN}} Software},
url = {https://www.eclipse.org/paho/},
urldate = {2020-07-16},
file = {/home/norangebit/Zotero/storage/BC7DTMJT/paho.html}
}
@online{InstallationBetterBibTeX,
title = {Installation :: {{Better BibTeX}} for {{Zotero}}},
url = {https://retorque.re/zotero-better-bibtex/installation/},
urldate = {2020-07-07},
file = {/home/norangebit/Zotero/storage/4SV9VW2H/installation.html}
}
@online{KeyvalueData,
title = {Save Key-Value Data},
journaltitle = {Android Developers},
url = {https://developer.android.com/training/data-storage/shared-preferences},
urldate = {2020-07-22},
file = {/home/norangebit/Zotero/storage/N7AEME4M/shared-preferences.html},
langid = {english}
}
@online{NotificheDiEsposizione,
title = {Notifiche di esposizione: un aiuto alla lotta al COVID-19 - Google},
shorttitle = {Notifiche di esposizione},
url = {https://www.google.com/intl/en_us/covid19/exposurenotifications/},
urldate = {2020-07-12},
abstract = {Scopri come le Notifiche di esposizione, progettate da Google e Apple, consentono alle app di inviarti una notifica in caso di una tua probabile esposizione al COVID-19.},
file = {/home/norangebit/Zotero/storage/BXRM92VF/exposurenotifications.html},
langid = {italian}
}
@online{RoomPersistenceLibrary,
title = {Room {{Persistence Library}}},
journaltitle = {Android Developers},
url = {https://developer.android.com/topic/libraries/architecture/room},
urldate = {2020-07-10},
abstract = {Learn to use the Room Library},
file = {/home/norangebit/Zotero/storage/ZU9BFHZW/room.html},
langid = {english}
}
@online{ServicesOverview,
title = {Services Overview},
journaltitle = {Android Developers},
url = {https://developer.android.com/guide/components/services},
urldate = {2020-07-08},
file = {/home/norangebit/Zotero/storage/E42F6BVA/services.html},
langid = {english}
}
@software{TCNCoalitionTCN2020,
title = {{{TCNCoalition}}/{{TCN}}},
date = {2020-06-30T08:50:32Z},
origdate = {2020-03-31T18:18:05Z},
url = {https://github.com/TCNCoalition/TCN},
urldate = {2020-07-10},
abstract = {Specification and reference implementation of the TCN Protocol for decentralized, privacy-preserving contact tracing.},
organization = {{TCN Coalition}}
}

448
documentazione.md Normal file
View File

@ -0,0 +1,448 @@
# Protocollo TCN {#sec:tcn-protocol}
## Descrizione del protocollo
Il protocollo TCN [@TCNCoalitionTCN2020], Temporary Contact Number, è un protocollo di tracciamento dei contatti decentralizzato, ideato dalla TCN Coalition. Quest'ultima è una comunità di persone che durante l'emergenza COVID-19 hanno sviluppato questo protocollo per lo sviluppo di applicazioni per notificare l'esposizione al contagio.
Il protocollo non richiede informazioni personali ed è compatibile con autorità sanitarie.
I dispositivi degli utenti inviano un identificativo agli utenti vicini tramite Bluetooth e successivamente, se un utente è risultato positivo al contagio, può notificarlo ai suo contatti.
Per aumentare la scalabilità la TCN Coalition ha scelto di non generare randomicamente tcn, ma di generarli in modo deterministico da un seed.
In questo modo si riduce la dimensione del report da inviare, in quanto contiene solo le informazione necessarie per calcolare i tcn e non l'elenco intero di tcn.
L'utente può caricare diversi report di dimensioni minori in modo da non caricare l'intera cronologia dei contatti.
### Chiavi di autorizzazione e verifica
L'user agent crea una chiave di autorizzazione *rak* (report authorization key) e una chiave di verifica *rvk* (report verification key) attraverso la curva ellittica *Ed25519*.
A partire dalla rak è possibile ricavare la chiave di contatto iniziale tck_0.
```
tck_0 ← H_tck(rak)
```
dove `H_tck` è una funzione di hash con 256 bit di output che utilizza come separatore di dominio la rappresentazione in byte della stringa *H_TCK*.
### Chiave temporanea di contatto {#sec:tck}
Ogni report può contenere al massimo $2^{16}$ chiavi di contatto.
Partendo da un tcn può essere ricavato il prossimo come mostrato di seguito:
```
tck_i ← H_tck(rvk || tck_{i-1})
```
dove `||` indica una concatenazione.
### Numeri temporanei di contatto {#sec:tcn}
Per ogni tck viene generato un unico numero di contatto temporaneo (*tcn*) come mostrato di seguito:
```
tcn_i ← H_tcn(le_u16(i) || tck_i)
```
dove `H_tcn` è una funzione di Hash con 128 bit di output che utilizza come separatore di dominio la rappresentazione in byte della stringa *H_TCN* .
Dalla chiave rak è possibile generare la chiave rvk e la chiave tck_0, dalle quali è possibile generare le successive tck e quindi tutti i successivi tcn.
### Report {#sec:report}
Quando viene richiesto di caricare i dati dell'utente, è possibile eseguire l'upload di un report compatto. Infatti grazie alla derivazione deterministica, è possibile inviare tutti gli identificativi utilizzati nel periodo `j1` e `j2`, caricando unicamente la `rvk`, `tck_{j1-1}`, e i due indici `j1` e `j2`.
Di seguito è illustrato come costruire il report:
```
report ← rvk || tck_{j1-1} || le_u16(j1) || le_u16(j2) || memo
```
dove `memo` è una stringa di byte di lunghezza variabile che va da 2 a 257 byte.
Inoltre si utilizza il rak per produrre una firma `sig` per il report e verrà inviata al server la concatenazione di sig e report.
Poiché la rvk è contenuta all'interno del report, chiunque può verificare l'integrità del report e ricavare i vari tcn.
## Implementazione del protocollo per la JVM
Al fine di utilizzare il protocollo precedentemente descritto all'interno dell'applicazione Android, ne è stato sviluppato un'implementazione per la *Java Virtual Machine*.
La gestione della coppia di chiavi derivate dalla curva ellittica *Ed25519* è stata affidata alla libreria ***ed25519-elisabeth*** [@CryptographycafeEd25519elisabeth2020].
Le chiavi private e pubbliche prodotte sono state *wrappate* rispettivamente nelle classi `ReportAuthorizationKey` e `ReportVerificationKey`.
Questa scelta non solo ha permesso di utilizzare nomi dal maggiore significato rispetto al dominio applicativo, ma anche di nascondere l'implementazione della curva *Ed25519* in modo da disaccoppiare l'interfaccia della libreria crittografica da quella utilizzata per il protocollo TCN.
Come illustrato nella @sec:tck, a partire dalla chiave di autorizzazione è possibile ricavare la `TemporaryContactKey` iniziale[^tck-0].
Ciò può essere fatto attraverso la funzione `baseTemporaryContactKey()`, la cui implementazione è riportata nel @lst:tck-0.
Invece, partendo da una chiave di contatto generica, è possibile ricavare la successiva chiave di contatto attraverso il metodo `nextTemporaryContactKey()` riportato nel listato @lst:next-tck.
[^tck-0]: La chiave temporanea iniziale viene ricavata a partire dalla sola *rak* e da essa non è generato nessun numero temporaneo di contatto.
``` {.kotlin #lst:tck-0 caption="Derivazione della prima tck."}
fun baseTemporaryContactKey(): TemporaryContactKey {
val hmac = MessageDigest.getInstance("SHA-256").apply {
update(Const.H_TCK_DOMAIN_SEPARATOR)
update(key.toByteArray())
}
return TemporaryContactKey.createFromByteArray(
hmac.digest(),
0
)
}
```
``` {.kotlin #lst:next-tck caption="Generazione della prossima tck."}
fun nextTemporaryContactKey(
rvk: ReportVerificationKey
): TemporaryContactKey {
val hmac = MessageDigest.getInstance("SHA-256").apply {
update(Const.H_TCK_DOMAIN_SEPARATOR)
update(rvk.toByteArray())
update(key)
}
return TemporaryContactKey(
hmac.digest(),
index.inc()
)
}
```
Sempre a partire dalla tck è possibile ricavare il numero di contatto temporaneo (tcn) e da esso settare il campo UUID utilizzato per il broadcast del beacon bluetooth.
Questa operazione può essere eseguita mediante la funzione `deriveTemporaryContactNumber()` la cui implementazione è stata riportata nel @lst:derive-tcn.
``` {.kotlin #lst:derive-tcn caption="Derivazione del numero di contatto temporaneo."}
fun deriveTemporaryContactNumber(): TemporaryContactNumber {
val hmac = MessageDigest.getInstance("SHA-256").apply {
update(Const.H_TCN_DOMAIN_SEPARATOR)
update(index.toLeByteArray())
update(key)
}
return TemporaryContactNumber(
hmac.digest().sliceArray(0 until 16),
index
)
}
```
Un'altra componente fondamentale dell'implementazione del protocollo TCN è la classe `Report`, infatti tramite essa è possibile generare il report firmato che poi sarà inviato al server.
Inoltre questa classe mette a disposizione una serie di funzioni di utilità come `generateContactNumbers()` e `toReportData()` che facilitano l'estrazione delle informazioni contenute all'interno del report.
Infine la classe report fornisce anche un metodo statico, `readReportDataFromByteArray()`, attraverso il quale altre componenti applicative sono in grado di recuperare le informazioni di un report contenute all'interno di un array di bytes.
L'implementazione di questo metodo è riportata nel listato @lst:read-report.
``` {.kotlin #lst:read-report caption="Lettura dei dati di un report da un ByteArray."}
fun readReportDataFromByteArray(bytes: ByteArray): ReportData {
val buffer = ByteBuffer.wrap(bytes).apply {
order(ByteOrder.LITTLE_ENDIAN)
}
val rvk = ReportVerificationKey
.createFromByteArray(buffer.read(32))
val tckBytes = buffer.read(32)
val from = buffer.short
val until = buffer.short
val memoType = buffer.get()
val memoData = String(buffer.read(buffer.get().toInt()))
return ReportData(
rvk,
TemporaryContactKey
.createFromByteArray(tckBytes, from.dec()),
from,
until,
memoData
)
}
```
# Applicazione
L'applicazione permette di tracciare i contatti degli utenti attraverso l'impiego del Bluetooth Low Energy (BLE).
In particolare lo smartphone di ogni utente esegue il broadcast e la scansione di beacon bluetooth.
In questo modo quando due utenti entrano nel raggio di azione del bluetooth il contatto verrà memorizzato sui rispettivi dispositivi.
L'applicazione prevede differenti modalità di funzionamento, ognuna delle quali garantisce un diverso livello di privacy.
Nella modalità di funzionamento ***A*** ogni qual volta si verifica un contatto l'applicazione si occupa di notificare immediatamente l'evento al server in modo tale che esso possa essere aggiunto al database remoto.
Questa modalità è quella meno *privacy friendly* in quanto la comunicazione avviene in *real-time* e all'interno del messaggio scambiato viene riportato sia il *tcn* dell'utente sia quello della persona incontrata.
La modalità ***B*** prevede lo scambio delle stesse informazioni previste per la modalità precedente, ma solo se richiesto dalle autorità sanitarie.
In questo modo non solo si evita che i dati siano catturati dal server in *real-time*, ma si espongono le informazioni dell'utente solo quando queste sono strettamente necessarie.
Sia in questa modalità, che nella precedente si è scelto di non ruotare i *tcn* identificativi degli utenti in modo da facilitare la generazione del grafo sul server.
Questa soluzione può mettere a repentaglio la privacy degli utenti ed essere sfruttata da *avversari* per ottenere informazioni sulle abitudini degli utilizzatori[^catena-negozi].
[^catena-negozi]: Per esempio una catena di negozi attraverso l'impiego di uno scanner bluetooth potrebbe ricostruire la *fedeltà* degli utenti, conoscere i settori del negozio preferiti ecc.
L'ultima modalità, la ***C***, è quella che tutela maggiormente la privacy degli utilizzatori attraverso due accorgimenti:
- Rotazione dei *tcn*
- Matching locale
La generazione dei *tcn* avviene attraverso una derivazione deterministica come visto nella @sec:tcn-protocol, in modo tale da avere lo stesso livello di privacy di una soluzione randomica, ma con una migliore scalabilità.
Mentre il matching locale permette di condividere il minor numero di informazioni possibili e solo quando questo è strettamente necessario.
Infatti in questa modalità l'applicazione carica le informazioni sul server solo in seguito alla richiesta delle autorità sanitarie.
Inoltre a differenza delle prime due modalità è previsto l'upload unicamente dei *tcn* che il dispositivo ha assunto nel tempo, in questo modo il server non è in grado di conoscere o ricavare i contatti avuti dall'utente.
## API covid di Apple e Google
La prima scelta progettuale che abbiamo dovuto affrontare ha riguardato l'utilizzo o meno dell'API messa a disposizione da Apple [@AppleGooglePartner] e Google [@NotificheDiEsposizione].
Infatti i due giganti californiani hanno sviluppato in modo congiunto un protocollo che permettesse di tracciare i contatti degli utenti dei due sistemi operativi mobili più diffusi.
Questo protocollo ricorda per molte caratteristiche il protocollo TCN illustrato precedentemente.
Entrambi i protocolli ricavano gli identificativi (*rolling proximity identifier* nel protocollo di Apple e Google) in modo deterministico a partire da delle chiavi (*temporary exposure keys*).
I due protocolli differiscono nel numero di identificativi ricavati da ciascuna chiave; come visto nella @sec:tcn il protocollo TCN ricava un unico tcn per chiave, mentre l'altro protocollo permette di ricavare un numero imprecisato di identificativi.
Un'ulteriore differenza risiede nella derivazioni delle chiavi, che nel protocollo TCN è deterministica, mentre in quello di Apple e Google non è specificato.
Oltre al protocollo, le due società, hanno fornito agli sviluppatori un'API che permettesse alle applicazioni di utilizzare il protocollo descritto nel paragrafo precedente.
Sfortunatamente l'API non ci avrebbe permesso di implementare tutte e tre le modalità di funzionamento, ma solo l'ultima che si basa su un matching locale.
Questa caratteristica, unita alle regole stringenti di utilizzo imposte della libreria[^regole-api-apple-google] ci ha condotto alla scelta di implementare le varie funzionalità in maniera indipendente.
[^regole-api-apple-google]: Le due società californiane consentono lo sviluppo di applicazioni che fanno uso della loro API solo ad enti governativi e impongo un numero massimo di applicazioni per nazione pari ad uno.
Dalla documentazione ufficiale non è ben chiaro se questi vincoli riguardino solo la pubblicazione sugli store o anche lo sviluppo.
## Interazione via Bluetooth
L'interazione tra l'hardware bluetooth del dispositivo e l'applicazione è stata gestita attraverso l'impiego della libreria *Android Beacon Library* [@AndroidBeaconLibrary] che permette di gestire più facilmente le operazioni con beacon bluetooth.
Inoltre per rendere l'applicazione più funzionale, e quindi garantirne il funzionamento anche in background o a schermo spento è stato utilizzato un *foreground service* [@ServicesOverview], che consente di mantenere in *primo piano* le operazioni di trasmissione e scansione anche quando l'applicazione non lo è.
Data la natura variegata di Android, le diverse implementazioni del sistema operativo adoperate dai vari produttori non si comportano sempre nello stesso modo, motivo per il quale alcuni dispositivi tenderanno a terminare, o mettere in pausa ugualmente l'applicazione[^dont-kill-my-app].
Potendo operare unicamente nello spazio utente non è stato possibile superare questi limiti.
[^dont-kill-my-app]: Molti produttori Android per aumentare la durata della batteria dei propri dispositivi tendono a stoppare e ridurre le funzionalità delle applicazioni. Maggiori dettagli possono essere trovati al seguente link \url{https://dontkillmyapp.com}.
Tutte le funzionalità legate al bluetooth sono state *incapsulate* all'interno della classe `BluetoothManager`.
L'interfaccia di questa classe espone due metodi, `startService()` e `stopService()` che consentono di avviare e stoppare sia la scansione che la trasmissione del beacon.
Poiché queste operazioni vanno ad interagire con le funzionalità del sistema operativo, l'istanza di questa classe deve essere collegata ad un oggetto di tipo `Context`.
Si è scelto di collegare l'oggetto `BluetoothManager` all'*application* e non ad una `Activity` in quanto i servizi devono essere utilizzati anche quando non sono presenti *activity* in *foreground*.
Per questo motivo è stata sviluppata anche una classe `BluetoothApplication` che va ad estendere le funzionalità di `Application` e fornisce a sua volta due metodi di start e stop che vanno a richiamare quelli esposti da `BluetoothManager` in modo tale da rendere possibile il controllo dei servizi legati al bluetooth anche da altre componenti dell'applicazione.
I beacon bluetooth gestiti dall'applicazione sono caratterizzati dal seguente formato `s:0-1=2a,i:2-17` dove il parametro `s` specifica i bit destinati al tipo di servizio e il suo valore, mentre il parametro `i` specifica i bit destinati all'UUID.
### Trasmissione
Il dispositivo dell'utente deve eseguire il **broadcast** di un beacon bluetooth contenete nel campo UUID il *tcn* identificativo.
Questa operazione è stata svolta attraverso la classe `BeaconTransmitter` messa a disposizione dalla *Android Beacon Library*.
Inoltre per la modalità di funzionamento *C* è stato necessario prevedere un meccanismo di rotazione delle chiavi di contatto.
Questa rotazione viene settata attraverso la funzione `rotateTCN()` (@lst:rotate-tcn) che sfrutta un `Handler` per programmare la rotazione del *tcn*.
``` {.kotlin #lst:rotate-tcn caption="Codice necessario alla rotazione del tcn."}
private fun rotateTCN() {
val advertiseHandler = Handler()
val changeTCN: Runnable = object : Runnable {
override fun run() {
tcnManager.nextTcn()
startAdvertising()
advertiseHandler.postDelayed(
this,
TCNManager.ELAPSE_BETWEEN_NEW_TCN
)
}
}
advertiseHandler.postDelayed(
changeTCN,
TCNManager.ELAPSE_BETWEEN_NEW_TCN
)
}
```
La scelta della frequenza di *advertising* è stata dettata dai vincoli tracciati dall'API di Android [@AdvertiseSettings].
Infatti la libreria permette di trasmettere un beacon con una frequenza di 1 *Hz*, 3 *Hz* o 10 *Hz*.
Fortunatamente questi vincoli non si sono rilevati troppo limitanti infatti la frequenza di un Hertz, quindi un beacon trasmetto ogni secondo, permette di avere una buona trasmissione e di risparmiare batteria.
Inoltre in fase di scanning evita che siano registrate più interazioni nello stesso ciclo.
Sempre attraverso l'API di Android è stata settata la potenza di trasmissione del beacon.
Anche in questo caso la scelta era limitata a poche alternative:
- HIGH
- MEDIUM
- LOW
- ULTRA_LOW
Come è possibile dedurre anche dai nomi dei vari livelli, l'API non fornisce nessuna stima quantitativa[^dispositivi-non-omogenei], ma solo delle indicazioni qualitative delle intensità del segnale trasmesso.
L'individuazione del livello più adatto è stata svolta per via sperimentale utilizzando quattro dispositivi differenti[^dispositivi-usati].
I due livelli più alti sono stati immediatamente scartati in quanto permettevano di rilevare i beacon a distanze elevate cosa che avrebbe minato la bontà dell'applicazione.
Con il livello ULTRA_LOW si è notato che venivano rilevate unicamente le interazioni inferiori al metro in contesti *free space*.
Poiché l'organizzazione mondiale della sanità raccomanda una distanza di almeno un metro [@AdvicePublicCOVID19] questo livello di trasmissione non consente di rilevare contatti potenzialmente a rischio.
Per questo motivo si è scelto di utilizzare il livello LOW che permette di rilevare contatti fino a circa due metri.
[^dispositivi-non-omogenei]: D'altronde, data la natura non omogenea dei vari dispositivi Android, una stima quantitativa sarebbe stata impossibile da ottenere.
[^dispositivi-usati]: Sono stati usati i seguenti dispositivi; One Plus 3T con versione di Android 9, Xiaomi Mi 5 con Android 8, Xiaomi Mi A2 Lite con Android 10, Samsung Galaxy A5 con Android 7.
### Scansione
Le operazioni di scansione, effettuate tramite l'ausilio della classe `BeaconManager`, sono meno limitate dalle funzionalità dell'API e per questo motivo c'è stata maggiore libertà di scelta.
In particolare è stato possibile settare sia l'intervallo temporale che deve intercorrere tra una scansione e la successiva, sia la durata della singola scansione.
Si è scelto di far trascorrere un minuto tra una scansione e la prossima e di avere una scansione della durata di un secondo.
Per quanto detto già in precedenza in base ai vari dispositivi e alle varie condizioni di funzionamento l'intervallo tra una scansione e la successiva potrebbe essere più ampio rispetto a quello stabilito.
Entrambi i parametri sono stati settati tramite una costante in modo tale da poter configurare facilmente il comportamento dell'applicazione.
Quando l'applicazione rivela un beacon nelle vicinanze esso viene trasmesso ad un'ulteriore componente applicativa tramite l'impiego del `LocalBroadcastManager` [@BroadcastsOverview].
Questa componente non consuma direttamente il beacon, ma ha il compito di smistarlo ad ulteriori componenti in base alla modalità di funzionamento dell'applicazione.
Nel caso della modalità *A* il beacon viene trasmesso alla classe `NetworkReceiver` che si occupa di trasmettere il contatto al server remoto.
Mentre nel caso delle modalità *B* e *C* il beacon viene consumato dalla classe `StoreReceiver` la quale si occupa della memorizzazione permanente del contatto all'interno di un database locale.
### Stima della distanza
In base all'intensità dell segnale (***rssi***) misurato dal dispositivo ricevente è possibile ottenere una stima della distanza che intercorre tra chi invia il beacon e chi lo riceve attraverso l'@eq:distanza.
Per poter calcolare la distanza è necessario conoscere anche il valore di $n$ e $TxPower$.
$n$ è una costante che generalmente assume valori compresi tra uno e quattro e ci permette di modellare i diversi ambienti in cui si può operare.
Generalmente s'impone $n$ pari a due quando si ipotizza di lavorare in ambienti *free space*.
$$
d = 10^{\frac{TxPower - rssi}{10 \cdot n}}
$$ {#eq:distanza}
$TxPower$ è la potenza di trasmissione nominale che si misurerebbe alla distanza di un metro dalla sorgente del segnale.
Il valore di $TxPower$ deve essere precedentemente ricavato per ogni emettitore e deve essere inviato all'interno del beacon bluetooth.
Lavorando con dispositivi eterogenei tra di loro non è stato possibile calcolare in modo esatto questo valore, ma si è scelto di utilizzare il valore $-59$ poiché si adattava mediamente a tutti i dispositivi utilizzati in fase di test.
## Memorizzazione ID
In base alla modalità di funzionamento l'applicazione deve memorizzare diversi tipi di dati.
La gestione della persistenza è stata realizzata attraverso la libreria ***Room*** [@RoomPersistenceLibrary], una componente di *Jetpack* [@AndroidJetpackAndroid] la suite di librerie supportate da *Google*.
*Room* fornisce un layer astratto che permette di operare più facilmente con il database *SQLite* sottostante.
La memorizzazione dei contatti è avvenuta tramite lo schema riportato nel @lst:contact-data.
Questi dati vengono conservati solo nella modalità di funzionamento *B* e *C* poiché nella modalità *A* il contatto viene comunicato immediatamente al server per cui non è necessaria una memorizzazione locale.
Per il timestamp si è scelto di utilizzare un `Long` che misura i secondi trascorsi dalla *epoch unix* e che fa riferimento al *Greenwich Mean Time* (GMT).
``` {.markdown #lst:contact-data caption="Schema utilizzato per la memorizzazione dei dati di contatto."}
- `id`: Int [PrimaryKey | AutoGenerate]
- `uuidReceiver`: String
- `uuidSender`: String
- `rssi`: Int
- `txPower`: Int
- `timestamp`: Long
```
Nella modalità *C* è necessario memorizzare anche le tck utilizzate nel corso del tempo (si veda la @sec:tck per maggiori dettagli).
Oltre alla memorizzazione della tck, tramite un array di byte, è necessario memorizzare anche l'indice associato ad essa e il timestamp di primo utilizzo.
Lo schema della tabella utilizzata per la memorizzazione di queste informazioni è riportato nel @lst:tck-data.
Anche in questo caso, per quanto riguarda il timestamp, restano valide le considerazioni fatte in precedenza.
``` {.markdown #lst:tck-data caption="Schema utilizzato per la memorizzazione delle tck."}
- `index`: Short [PrimaryKey]
- `timestamp`: Long,
- `tck`: ByteArray
```
Questi dati persistenti sono stati acceduti mediante l'utilizzo di due *Data Access Object* (DAO).
Le interfacce dei DAO utilizzate sono riportate nei listati -@lst:dao-contact e -@lst:dao-tcn.
Oltre alla memorizzazione sul database sono state impiegate anche le *shared preferences* [@KeyvalueData] per memorizzare la modalità di funzionamento scelta dall'utente, la *rak*, l'ultima *tck* e il *tcn* associato ad essa.
``` {.kotlin #lst:dao-contact caption="Interfaccia ContactDataDao."}
@Dao
interface ContactDataDao {
@Query("SELECT * FROM contact_data")
suspend fun getAllContactData(): List<ContactData>
@Query("SELECT * FROM contact_data WHERE timestamp >= :baseline")
suspend fun getNewerThan(baseline: Long): List<ContactData>
@Insert
suspend fun insert(cn: ContactData)
}
```
``` {.kotlin #lst:dao-tcn caption="Interfaccia TCNDataDao."}
@Dao
interface TCNDataDao {
@Query("SELECT * FROM tcn_data")
suspend fun getAllTCNData(): List<TCNData>
@Query("SELECT * FROM tcn_data WHERE `index` == :index")
suspend fun getByIndex(index: Short): TCNData
@Insert
suspend fun insert(tcnData: TCNData)
}
```
## Comunicazione report
La comunicazione con il server avviene mediante un broker MQTT fornito da un altro gruppo di studenti.
Come implementazione del client MQTT si è scelto di utilizzare *Paho* [@EclipsePahoMQTT], un client realizzato da Eclipse.
Questa libreria oltre a fornire un client MQTT per la JVM fornisce anche un *service* per Android che permette di sollevare lo sviluppatore da alcuni dettagli implementativi.
L'applicazione, all'interno dell'architettura, svolge il ruolo di *publisher* e si occupa della pubblicazione di tre tipologie di messaggi:
- ***Messaggi di contatto***:
utilizzati sia nella modalità *A* che nella *B*, permettono di notificare al server un contatto tra due utenti.
Nel caso della modalità *A* viene svolto un invio in *real-time*, mentre nella configurazione *B* è manuale e viene eseguito solo quando l'utente risulta essere contagiato.
Il contenuto di questi messaggi coincide con la rappresentazione JSON dei dati di contatto illustrati nel @lst:contact-data.
- ***Messaggi di report***:
utilizzati esclusivamente nella modalità *C* e sono inviati manualmente dall'utente quando risulta essere positivo.
Questi messaggi trasportano come *payload* la rappresentazione esadecimale del report TCN firmato discusso nella @sec:report e vengono inviati solo quando l'*upload* è richiesto dall'utente.
- ***Messaggi di esposizione***:
contengono l'identificativo associato al dispositivo e permettono di notificare lo stato di contagiato al server.
Questi messaggi sono inviati unicamente dalla modalità *A* poiché nella modalità *B* e *C* il caricamento dei dati locali di contatto implica lo stato di contagiato.
Anche in questo caso si è scelto di *wrappare* la libreria utilizzata all'interno di una classe sviluppata in proprio.
Poiché l'unica funzionalità di nostro interesse è la *publish* è stato necessario scrivere un'unica funzione statica che si occupa di eseguire quest'operazione.
Questa funzione, riportata nel @lst:mqtt-publish, permette di specificare il topic e il contenuto del messaggio da pubblicare.
Inoltre attraverso una *lambda expression* è possibile specificare come comportarsi in caso di errori.
Sempre dal @lst:mqtt-publish è possibile notare l'utilizzo del parametro `cleanSession` impostato a `false` e l'utilizzo dei *QoS* a livello uno.
Queste scelte sono state necessarie per garantire un corretto funzionamento con il resto dell'infrastruttura.
``` {.kotlin #lst:mqtt-publish caption="Funzione wrap che consente la publicazione di un messaggio MQTT."}
fun publish(
context: Context,
topic: String,
payload: ByteArray,
onFailure: () -> Unit = LOG_ERROR
) {
val clientId = MqttClient.generateClientId()
val client = MqttAndroidClient(
context.applicationContext,
BROKER_URL,
clientId
)
val option = MqttConnectOptions().apply {
isCleanSession = false
}
client.connect(option)
.actionCallback = object: IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken?) {
val msg = MqttMessage(payload).apply {
qos = 1
}
client.publish(topic, msg).apply {
actionCallback = Disconnect(client)
}
}
override fun onFailure(
asyncActionToken: IMqttToken?,
exception: Throwable?
) {
onFailure()
}
}
}
```
Le funzionalità di rete sono state testate attraverso l'impiego di un broker pubblico (`tcp://broker.hivemq.com:1883`) ed un'istanza locale di *ActiveMQ Artemis* inoltre è stato utilizzato il topic `exposed-test-topic` per la pubblicazione dei messaggi.
Entrambi i parametri sono stati settati tramite delle costanti e quindi possono essere modificati facilmente.
## Interfaccia utente
L'applicazione opera prevalentemente in background, ma comunque è dotata di una serie di elementi grafici che consentono all'utente di interagire con essa.
Quando l'applicazione viene avviata per la prima volta l'utente ha la possibilità di scegliere la modalità di funzionamento che desidera utilizzare (si veda @fig:ui-welcome).
Una volta compiuta questa scelta viene chiesto all'utente di concedere l'accesso alla posizione.
Sebbene l'applicazione non utilizzi il GPS o altri strumenti di posizionamento ciò si rende necessario al fine di abilitare la scansione dei beacon BLE anche in background.
![Schermata di benvenuto.](fig/welcome.jpg){#fig:ui-welcome width=130}
La schermata principale dell'applicazione, riportata in @fig:ui-main, si compone di tre elementi:
- `TextView` che indica la modalità di funzionamento.
- `Button` *start/stop* che consente di avviare o stoppare il servizio bluetooth.
Questo pulsante viene abilitato unicamente se sono stati concessi i permessi di accesso alla posizione.
- `Button` *exposed* consente all'utente di raggiungere l'activity, @fig:ui-upload, attraverso la quale è possibile comunicare al server il proprio stato di contagiato.
Nel caso della modalità *B* e *C* vengono caricati sul server anche i dati di contatto presenti sul dispositivo.
![Schermata principale.](fig/main.jpg){#fig:ui-main width=130}
![Schermata per l'upload.](fig/upload.jpg){#fig:ui-upload width=130}
# Riferimenti

BIN
fig/main.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
fig/upload.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
fig/welcome.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

13
header.yaml Normal file
View File

@ -0,0 +1,13 @@
---
lang: it-IT
papersize: a4
title: Documentazione dell'applicazione CovShield
author:
- Raffale Mignone
- Noemi Mincolelli
numbersections: true
toc: true
bibliography: bib.bib
csl: ieee.csl
---

400
ieee.csl Normal file
View File

@ -0,0 +1,400 @@
<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only">
<info>
<title>IEEE</title>
<id>http://www.zotero.org/styles/ieee</id>
<link href="http://www.zotero.org/styles/ieee" rel="self"/>
<link href="https://ieeeauthorcenter.ieee.org/wp-content/uploads/IEEE-Reference-Guide.pdf" rel="documentation"/>
<link href="https://journals.ieeeauthorcenter.ieee.org/your-role-in-article-production/ieee-editorial-style-manual/" rel="documentation"/>
<author>
<name>Michael Berkowitz</name>
<email>mberkowi@gmu.edu</email>
</author>
<contributor>
<name>Julian Onions</name>
<email>julian.onions@gmail.com</email>
</contributor>
<contributor>
<name>Rintze Zelle</name>
<uri>http://twitter.com/rintzezelle</uri>
</contributor>
<contributor>
<name>Stephen Frank</name>
<uri>http://www.zotero.org/sfrank</uri>
</contributor>
<contributor>
<name>Sebastian Karcher</name>
</contributor>
<contributor>
<name>Giuseppe Silano</name>
<email>g.silano89@gmail.com</email>
<uri>http://giuseppesilano.net</uri>
</contributor>
<contributor>
<name>Patrick O'Brien</name>
</contributor>
<contributor>
<name>Brenton M. Wiernik</name>
</contributor>
<category citation-format="numeric"/>
<category field="engineering"/>
<category field="generic-base"/>
<summary>IEEE style as per the 2018 guidelines, V 11.12.2018.</summary>
<updated>2020-06-15T03:21:46+00:00</updated>
<rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
</info>
<locale xml:lang="en">
<terms>
<term name="chapter" form="short">ch.</term>
<term name="presented at">presented at the</term>
<term name="available at">available</term>
</terms>
</locale>
<!-- Macros -->
<macro name="status">
<choose>
<if variable="page issue volume" match="none">
<text variable="status" text-case="capitalize-first" suffix="" font-weight="bold"/>
</if>
</choose>
</macro>
<macro name="edition">
<choose>
<if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
<choose>
<if is-numeric="edition">
<group delimiter=" ">
<number variable="edition" form="ordinal"/>
<text term="edition" form="short"/>
</group>
</if>
<else>
<text variable="edition" text-case="capitalize-first" suffix="."/>
</else>
</choose>
</if>
</choose>
</macro>
<macro name="issued">
<choose>
<if type="article-journal report" match="any">
<date variable="issued">
<date-part name="month" form="short" suffix=" "/>
<date-part name="year" form="long"/>
</date>
</if>
<else-if type="bill book chapter graphic legal_case legislation motion_picture song thesis" match="any">
<date variable="issued">
<date-part name="year" form="long"/>
</date>
</else-if>
<else-if type="paper-conference" match="any">
<date variable="issued">
<date-part name="month" form="short"/>
<date-part name="year" prefix=" "/>
</date>
</else-if>
<else>
<date variable="issued">
<date-part name="month" form="short" suffix=" "/>
<date-part name="day" form="numeric-leading-zeros" suffix=", "/>
<date-part name="year"/>
</date>
</else>
</choose>
</macro>
<macro name="author">
<names variable="author">
<name and="text" et-al-min="7" et-al-use-first="1" initialize-with=". "/>
<label form="short" prefix=", " text-case="capitalize-first"/>
<et-al font-style="italic"/>
<substitute>
<names variable="editor"/>
<names variable="translator"/>
</substitute>
</names>
</macro>
<macro name="editor">
<names variable="editor">
<name initialize-with=". " delimiter=", " and="text"/>
<label form="short" prefix=", " text-case="capitalize-first"/>
</names>
</macro>
<macro name="locators">
<group delimiter=", ">
<text macro="edition"/>
<group delimiter=" ">
<text term="volume" form="short"/>
<number variable="volume" form="numeric"/>
</group>
<group delimiter=" ">
<number variable="number-of-volumes" form="numeric"/>
<text term="volume" form="short" plural="true"/>
</group>
<group delimiter=" ">
<text term="issue" form="short"/>
<number variable="issue" form="numeric"/>
</group>
</group>
</macro>
<macro name="title">
<choose>
<if type="bill book graphic legal_case legislation motion_picture song" match="any">
<text variable="title" font-style="italic"/>
</if>
<else>
<text variable="title" quotes="true"/>
</else>
</choose>
</macro>
<macro name="publisher">
<choose>
<if type="bill book chapter graphic legal_case legislation motion_picture paper-conference song" match="any">
<group delimiter=": ">
<text variable="publisher-place"/>
<text variable="publisher"/>
</group>
</if>
<else>
<group delimiter=", ">
<text variable="publisher"/>
<text variable="publisher-place"/>
</group>
</else>
</choose>
</macro>
<macro name="event">
<choose>
<if type="paper-conference speech" match="any">
<choose>
<!-- Published Conference Paper -->
<if variable="collection-editor editor editorial-director issue page volume" match="any">
<group delimiter=", ">
<group delimiter=" ">
<text term="in"/>
<text variable="container-title" font-style="italic"/>
</group>
<text variable="event-place"/>
</group>
</if>
<!-- Unpublished Conference Paper -->
<else>
<group delimiter=", ">
<group delimiter=" ">
<text term="presented at"/>
<text variable="event"/>
</group>
<text variable="event-place"/>
</group>
</else>
</choose>
</if>
</choose>
</macro>
<macro name="access">
<choose>
<if type="webpage post post-weblog" match="any">
<choose>
<if variable="URL">
<group delimiter=" ">
<text variable="URL"/>
<group delimiter=" " prefix="(" suffix=")">
<text term="accessed"/>
<date variable="accessed">
<date-part name="month" form="short" strip-periods="false"/>
<date-part name="day" form="numeric-leading-zeros" prefix=" " suffix=", "/>
<date-part name="year" form="long"/>
</date>
</group>
</group>
</if>
</choose>
</if>
<else-if match="any" variable="DOI">
<text variable="DOI" prefix="doi: "/>
</else-if>
<else>
<group delimiter=". ">
<group delimiter=": ">
<text term="accessed" text-case="capitalize-first"/>
<date variable="accessed">
<date-part name="month" form="short" suffix=" "/>
<date-part name="day" form="numeric-leading-zeros" suffix=", "/>
<date-part name="year"/>
</date>
</group>
<text term="online" prefix="[" suffix="]" text-case="capitalize-first"/>
<group delimiter=": ">
<text term="available at" text-case="capitalize-first"/>
<text variable="URL"/>
</group>
</group>
</else>
</choose>
</macro>
<macro name="page">
<choose>
<if type="article-journal" variable="number" match="all">
<group delimiter=" ">
<text value="Art."/>
<text term="issue" form="short"/>
<text variable="number"/>
</group>
</if>
<else>
<group delimiter=" ">
<label variable="page" form="short"/>
<text variable="page"/>
</group>
</else>
</choose>
</macro>
<macro name="citation-locator">
<group delimiter=" ">
<choose>
<if locator="page">
<label variable="locator" form="short"/>
</if>
<else>
<label variable="locator" form="short" text-case="capitalize-first"/>
</else>
</choose>
<text variable="locator"/>
</group>
</macro>
<!-- Citation -->
<citation collapse="citation-number">
<sort>
<key variable="citation-number"/>
</sort>
<layout delimiter=", ">
<group prefix="[" suffix="]" delimiter=", ">
<text variable="citation-number"/>
<text macro="citation-locator"/>
</group>
</layout>
</citation>
<!-- Bibliography -->
<bibliography entry-spacing="0" second-field-align="flush">
<layout suffix=".">
<!-- Citation Number -->
<text variable="citation-number" prefix="[" suffix="]"/>
<!-- Author(s) -->
<text macro="author" suffix=", "/>
<!-- Rest of Citation -->
<choose>
<!-- Specific Formats -->
<if type="article-journal">
<group delimiter=", ">
<text macro="title"/>
<text variable="container-title" font-style="italic" form="short"/>
<text macro="locators"/>
<text macro="page"/>
<text macro="issued"/>
<text macro="status"/>
<text macro="access"/>
</group>
</if>
<else-if type="paper-conference speech" match="any">
<group delimiter=", ">
<text macro="title"/>
<text macro="event"/>
<text macro="issued"/>
<text macro="locators"/>
<text macro="page"/>
<text macro="status"/>
<text macro="access"/>
</group>
</else-if>
<else-if type="report">
<group delimiter=". ">
<group delimiter=", ">
<text macro="title"/>
<text macro="publisher"/>
<group delimiter=" ">
<text variable="genre"/>
<text variable="number"/>
</group>
<text macro="issued"/>
</group>
<text macro="access"/>
</group>
</else-if>
<else-if type="thesis">
<group delimiter=", ">
<text macro="title"/>
<text variable="genre"/>
<text macro="publisher"/>
<text macro="issued"/>
</group>
</else-if>
<else-if type="webpage post-weblog post" match="any">
<group delimiter=", " suffix=". ">
<text macro="title"/>
<text variable="container-title" font-style="italic"/>
<text macro="issued"/>
</group>
<text macro="access"/>
</else-if>
<else-if type="patent">
<group delimiter=", ">
<text macro="title"/>
<text variable="number"/>
<text macro="issued"/>
</group>
</else-if>
<!-- Generic/Fallback Formats -->
<else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
<group delimiter=", " suffix=". ">
<text macro="title"/>
<text macro="locators"/>
</group>
<group delimiter=", ">
<text macro="publisher"/>
<text macro="issued"/>
<text macro="page"/>
</group>
</else-if>
<else-if type="article-magazine article-newspaper broadcast interview manuscript map patent personal_communication song speech thesis webpage" match="any">
<group delimiter=", ">
<text macro="title"/>
<text variable="container-title" font-style="italic"/>
<text macro="locators"/>
<text macro="publisher"/>
<text macro="page"/>
<text macro="issued"/>
</group>
</else-if>
<else-if type="chapter paper-conference" match="any">
<group delimiter=", " suffix=", ">
<text macro="title"/>
<group delimiter=" ">
<text term="in"/>
<text variable="container-title" font-style="italic"/>
</group>
<text macro="locators"/>
</group>
<text macro="editor" suffix=" "/>
<group delimiter=", ">
<text macro="publisher"/>
<text macro="issued"/>
<text macro="page"/>
</group>
</else-if>
<else>
<group delimiter=", " suffix=". ">
<text macro="title"/>
<text variable="container-title" font-style="italic"/>
<text macro="locators"/>
</group>
<group delimiter=", ">
<text macro="publisher"/>
<text macro="page"/>
<text macro="issued"/>
<text macro="access"/>
</group>
</else>
</choose>
</layout>
</bibliography>
</style>

9
makefile Normal file
View File

@ -0,0 +1,9 @@
out/documentation.pdf: header.yaml documentazione.md out
pandoc header.yaml documentazione.md \
-F pandoc-crossref \
-F pandoc-citeproc \
-o out/documentazione.pdf
out:
mkdir out