Digipost-adresser og person-alias

Digipost-adressen er en permanent identifikator for en mottaker, som ikke vil endre seg over tid. Person-aliaset er en identifikator for en person som vi klarer å identifisere, men som ikke er registrert.

1. Digipost-adresse

Digipost-adressen er en permanent identifikator for en mottaker, som ikke vil endre seg over tid. Selv om mottakeren får en ny Digipost-adresse i forbindelse med navneendring, vil den gamle adressen fortsatt være gyldig.

En Digipost-adresse består av en navnedel og en identifikatordel separert med ‘#’: <navne-del>#<identifikator-del>

Navnedelen kan maksimalt inneholde 35 tegn (bokstaver og punktum) og identifikatordelen består alltid av fire tegn (tall og bokstaver). Totalt kan Digipost-adressen derfor inneholde inntil 40 tegn. I adressene skilles det ikke mellom små og store bokstaver, men de presenteres vanligvis slik at navnedelen skrives med små bokstaver, mens bokstavene i identifikatordelen er store.

Digipost-adresser kan inneholde bokstavene æ, ø og å. Dersom du ønsker å unngå bruk av de særnorske bokstavene, kan du bytte ut æ med ae, ø med oe og å med aa i Digipost-adressen og la resten av adressen stå uforandret, så hvis en Digipost-adresse er oppgitt som øystein.ås#1234 vil også oeystein.aas#1234 være en gyldig Digipost-adresse for samme person. For Digipost-adresser som inneholder særnorske bokstaver, vil maksimallengden reduseres, slik at du kan være sikker på at alle Digipost-adresser passer inn i et felt på 40 bytes, også om de lagres som utf-8.

2. Person-alias

Person-aliaset er en identifikator for en person som vi klarer å identifisere ved hjelp Postens adresseregister, men som ikke er Digipost-bruker. Ved å ta vare på person-aliaset for en mottaker vil du være sikker på å treffe vedkommende når han eventuelt registrerer seg hos Digipost. Person-alias har samme format som Digipost-adresser, men inneholder i motsetning til disse ingen identifiserende informasjon. Aliasene består av tjue bokstaver (a-z) etterfulgt av ‘#’ og fire tegn (tall og bokstaver).

3. Verifikasjon av adresser og alias

Identifikatordelen inneholder et kontrollsiffer, som regnes ut basert på resten av adressen. Dette kontrollsifferet sikrer blant annet at dersom man gjør én tastefeil når man skriver inn en gyldig Digipost-adresse, vil det ikke kunne resultere i en annen gyldig Digipost-adresse.

Du kan selv verifisere at Digipost-adresser kundene dine oppgir, er gyldige ved å sjekke at det er samsvar mellom navnedelen og identifikatordelen. Dersom du sender en ugyldig Digipost-adresse til Digipost, vil du få en feilmelding som sier at Digipost-adressen er ugyldig.

Valideringsalgoritmen er beskrevet i den følgende eksempelkoden:



import java.text.Normalizer;
import java.util.regex.Pattern;

/**
 * Validerer at en Digipost-adresse eller et person-alias er gyldig, dvs. at det
 * har riktig lengde, ikke inneholder ulovlige tegn, og at det er samsvar mellom
 * navnedel og identifikatordel. At en Digipost-adresse er gyldig betyr ikke
 * nødvendigvis at det er en adresse som faktisk benyttes.
 */
public class DigipostadresseValidator {
    private static final int MIN_NAVNELENGDE = 3;
    private static final int MAX_NAVNELENGDE = 35;
    private static final int IDENTIFIKATORLENGDE = 4;

    private static final Pattern NAVNEMOENSTER = Pattern.compile("[a-zæøå]+(\.[a-zæøå]+)+");
    private static final Pattern PERSONALIAS_NAVNEMOENSTER = Pattern.compile("[a-z]{20}");

    private static final String TEGNSETT_I_NAVN = ".abcdefghijklmnopqrstuvwxyz";
    private static final String TEGNSETT_I_IDENTIFIKATOR = "0123456789ABCDEFGHJKMNPQRSTUVWXYZ";
    private static final int[] VEKTER_FORAN = { 25, 23, 13, 14, 16, 17, 19, 20, 10, 8, 7, 5, 4, 2, 1, 32, 31, 29, 28, 26, 25, 23, 13, 14,
            16, 17, 19, 20, 10, 8, 7, 5, 4, 2, 1 };
    private static final int[] VEKTER_BAK = { 5, 4, 2, 1 };
    private static final int MODULUS = 33;

    public static boolean erGyldig(final String digipostadresse) {
        String normalisertAdresse = Normalizer.normalize(digipostadresse, Normalizer.Form.NFC);

        String[] array = normalisertAdresse.split("#");
        if (array.length != 2) {
            return false;
        }

        String navn = substituerNorskeBokstaver(array[0].toLowerCase());
        String identifikator = array[1].toUpperCase();

        if (navn.length() < MIN_NAVNELENGDE || navn.length() > MAX_NAVNELENGDE) {
            return false;
        }
        if (identifikator.length() != IDENTIFIKATORLENGDE) {
            return false;
        }

        if (!NAVNEMOENSTER.matcher(navn).matches() && !PERSONALIAS_NAVNEMOENSTER.matcher(navn).matches()) {
            return false;
        }

        int a = sjekksum(navn, MAX_NAVNELENGDE, TEGNSETT_I_NAVN, VEKTER_FORAN);
        int b = sjekksum(identifikator, IDENTIFIKATORLENGDE, TEGNSETT_I_IDENTIFIKATOR, VEKTER_BAK);
        if (a == -1 || b == -1) {
            return false;
        }
        int sjekksum = (a + b) % MODULUS;
        return sjekksum == 0;

    }

    private static String substituerNorskeBokstaver(final String navn) {
        return navn.replaceAll("æ", "ae").replaceAll("ø", "oe").replaceAll("å", "aa");
    }

    private static int sjekksum(final String streng, final int maxLengde, final String tegnsett, final int[] vekter) {
        int[] verdier = new int[maxLengde];
        for (int i = 0; i < streng.length(); i++) {
            int index = i + maxLengde - streng.length();
            verdier[index] = tegnsett.indexOf(streng.charAt(i));
            if (verdier[index] == -1) {
                return -1;
            }
        }
        return indreprodukt(vekter, verdier);
    }

    private static int indreprodukt(final int[] a, final int[] b) {
        int length = Math.min(a.length, b.length);
        int sum = 0;
        for (int i = 0; i < length; i++) {
            sum += a[i] * b[i];
        }
        return sum;
    }
}