Skip to main content

KODI Addons - NPO Uitzending gemist

·900 words·5 mins
Bas Magré
Author
Bas Magré
Father, happily married, DevOps engineer, C# developer, Python hobbyist, ex Oracle developer. Open-source freak, Opel Kadett C and ‘Hack the planet’ as a hobby.

Intro
#

Een stukje uitleg over de addon plugin.video.uzg voor Kodi. Deze blijf ik aanvullen als er (grote) dingen veranderen.

Addon in kodi-repo
#

In 2013 had ik de addon geschreven aangezien in mijn televisie abonnement had stop gezet. Met een paar aanpassingen aan mijn pull-request was deze een lange tijd zelfs opgenomen in de officiële addons repo van Kodi.

Tegenslag / Stoppen publieke addon
#

Maar helaas kwam daar na 5 jaar in eind november 2018 een einde aan. De NPO had namelijk de voorwaarden aangepast. Zover ik het nu kan lezen mag er geen publieke plugins/addons meer gemaakt worden. Gelukkig mag dit nog wel steeds voor eigen gebruik, er staat nergens dat dit niet mag! De app was ook “verbeterd”, je kan niet meer al het verkeer aftappen. Nu liep al het verkeer netjes via https, maar op Android Telefoons van versie 5 en lager, kan zelf “root” certificaten toevoegen. Dus we gingen naar “ZAP > Tools > Options > Dynamic SSL Certificates” en exporteerde het certificaat. We zette deze op de Android telefoon en al het verkeer was weer leesbaar.

Wat je hier doet, is al je verkeer via je proxy laten lopen, op je pc ook “decoderen” en opnieuw “coderen” mijn jouw certificaat. Je kan namelijk niet het certificaat van NPO gebruiken, je hebt immers de “private-key/geheime sleutel” niet. Je doet letterlijk een man-in-the-middle attack.

De Api was totaal veranderd, tevens de voorwaarden. Volgens de nieuwe voorwaarden mocht wat ik deed helaas niet meer. Netjes een verzoek gedaan bij Kodi om mijn addon “broken” te melden.

Natuurlijk kon ik privé gewoon doorgaan met mijn addon.

DRM
#

Alsof de tegenslag van november 2018 nog niet genoeg was, maart 2019 ging NPO over op DRM. Alles werkte nog, behalve de video-stream uitvragen. Dit moest ik dus weer uitzoeken. De app was nog beter beveiligt, ze doen nu aan “Certificate Pinning”, kortom je kan er niet tussen in gaan zitten met je eigen zap-ssl-certificaat. Dit was niet zo fijn. Uiteindelijk de Andoid App van de NPO moeten decompileren. Gelukkig kan dit online (hoef je de tools niet te installeren). Helaas hadden ze gebruik gemaakt van “code obfuscation (niet leesbaar maken van code)”, maar dat weerhield mij niet. Het koste mij alleen wat meer tijd. Ik kwam er achter hoe de video’s nu werden opgevraagd, met deze informatie kon ik mijn addon weer aanpassen.

Code uit de Android App

    public NedforceCatalog(OkHttpClient okHttpClient, NpoPlayerConfig npoPlayerConfig) {
        this._httpClient = okHttpClient;
        this._config = npoPlayerConfig;
        switch (this._config.getEnvironment()) {
            case 1:
                okHttpClient = "https://api.npobeta.nl";
                break;
            case 2:
                okHttpClient = "https://start-api.npo.nl";
                break;
            default:
                okHttpClient = "https://npo-api.staging.egeniq.com";
                break;
        }
        this._baseUrl = HttpUrl.parse(okHttpClient);
    }
en

    public void getStreamForAsset(final String str, String str2, String str3, boolean z, boolean z2, int i, final CatalogCallback<NpoStream> catalogCallback) {
        HttpUrl build = this._baseUrl.newBuilder().addPathSegment("media").addPathSegment(str).addPathSegment("stream").build();
        JSONObject jSONObject = new JSONObject();
        JSONObject jSONObject2 = new JSONObject();
        try {
            jSONObject.put(Scopes.PROFILE, str2);
            str2 = true;
            if (z) {
                jSONObject2.put("startOver", true);
            }
            jSONObject.put("options", jSONObject2);
            if (!TextUtils.isEmpty(str3)) {
                jSONObject.put("ageRestriction", str3);
            }
            if (z2) {
                if (this._config == null || this._config.getPlayerOptions() == null || TextUtils.isEmpty(this._config.getPlayerOptions().getEncryptionType()) != null) {
                    GlobalLogger.m6738a().m6749b(TAG, "skipCatalog = true requires to provide a DRM type!");
                } else {
                    jSONObject.put("skipCatalog", true);
                    jSONObject.put("useEncryption", this._config.getPlayerOptions().getEncryptionType());
                }
            }
            jSONObject.put("hasSubscription", i != 0);
            str3 = "hasPremiumSubscription";
            if (2 != i) {
                str2 = null;
            }
            jSONObject.put(str3, str2);
            jSONObject.put("platform", 2 == i ? Plan.PREMIUM : "npo");
            this._httpClient.newCall(new Builder().url(build).post(RequestBody.create(HttpClient.f5884b, jSONObject.toString())).build()).enqueue(new Callback() {
                public void onFailure(Call call, IOException iOException) {

Gelukkig was Kodi 18 net uit en daar kon je streams met DRM bekijken! Dus een paar avonden uitzoeken hoe je dat moest aanroepen en we konden weer video’s opstarten.

Security BUG (2019-2023)
#

Toen ik bezig was met uitzoeken hoe de “API’s” nu werkte. Ja API’s want de lijst met programma’s en afleveringen staat helemaal los van de uitvraag van de video-streams. Hierin zit dus ook een beveiligingsprobleem. de uitvraag voor de video-stream heeft geen kennis van de “API” van de NPO. Ook niet of je nu wel of geen “Premium” account hebt. (Lees NPO-plus). Kortom, je kan dus ZONDER dat je NPO-Plus account hebt WEL een NPO-Plus video opvragen. Vrij makkelijk zelfs, je past even een switch aan van “false” naar “true” in je bericht en klaar. Natuurlijk heb ik dit eerst netjes gemeld bij de NPO helemaal niks meer gehoord. Een direct gericht via Twitter, geen response en publiek bericht via twitter, geen reactie. Een bericht via Facebook, een hele korte reactie van “We zullen het doorgeven…” Toen kwam ik deze pagina tegen bij de NPO link. Hier wilde ik wel in komen te staan!, een mail naar de NPO dan maar in maart, april en in mei…, allemaal niks meer van gehoord.

Dus hier het beveiliging lek, ik vraag hier een video-stream op van “De Luizenmoeder”. Welke ik netjes terug krijg. Ook al mijn andere uitvragen komen nu met een 720p-stream terug i.p.v. een SD-stream.

hack NPO

Voor de netheid de “bug” niet doorgevoerd in mijn addon, maar dat is met 2 regels aanpassen wel te doen :)

Update: uiteindelijk november 2019 is de bug herkend en zijn er excuses gemaakt dat er zo traag gereageert was! alleen is de bug nooit opgelost. 1 december 2023 heeft de NPO een totaal andere API genomen, hierdoor werkt de “hack” niet meer.

Update december 2023
#

Ze hebben in december 2023 de hele api vervangen, ik heb de hele addon opnieuw mogen schrijven. Helaas geen “gratis” NPO-plus meer, maar nog steeds uitzending gemist op Kodi.