Learn more about disabling CORS, Navigator.mozTCPSocket
, and issues with Let’s Encrypt certificates on KaiOS
XMLHttpRequest
without CORS
There are several ways that dynamic web apps communicate with a back-end server. XMLHttpRequest (XHR) is the original method, used heavily in AJAX programming. XHR allows web apps to make a variety of HTTP requests like GET, PUT, POST, and DELETE, both synchronously (now deprecated) and asynchronously.
KaiOS fully supports XMLHttpRequest, including a few non-standard flags that can be provided to it’s constructor.
1let xhr = new XMLHttpRequest({
2 mozSystem: true,
3 mozAnon: true,
4 mozBackground: true,
5})
The first, and perhaps most useful flag is
mozSystem
. Privileged apps with the
systemXHR
permission are allowed to set this flag. Setting it to true
disables the same origin policy for the request, allowing requests without the usual Content Security Policy (CSP) errors.
Content Security Policy: The page’s settings blocked the loading of a resource at https://podlp.com/ (“connect-src”).
The second flag,
mozAnon
, works in tandem with the first. In fact, this flag is enabled whenever the mozSystem
flag is used (see
nsXMLHttpRequest.h). Setting mozAnon
ensures the request is sent anonymously, without cookies or authentication headers. It will also throw an error if you attempt to enable withCredentials
.
The final flag,
mozBackground
, is for background service requests. This causes the request to fail in cases where a security dialog (such as authentication or a bad certificate notification) would be shown.
Fetch
In addition to XHR, KaiOS also supports the Fetch
API. Similar to XHR, apps holding the systemXHR
permission are granted special treatment for requests made with the mode no-cors
. For instance, the
header list is not constrained and a sucessful request will resolve to a
basic response instead of an opaque response.
1fetch('https://google.com', {
2 method: 'GET',
3 mode: 'no-cors',
4})
Note: this behavior is only available on KaiOS 3.0 devices. For better compatability, developers will continue to prefer XMLHttpRequest with the mozSystem
flag which works on both KaiOS 2.5 and 3.0.
TCPSocket
API
KaiOS includes the non-standard navigator.mozTCPSocket
API for establishing lower-level TCP socket connections. This API is exposed to Privileged apps with the
tcp-socket
permission and allows developers to implement protocols on top of TCP like IMAP, IRC, POP, or HTTP.
Apps can both open and listen for socket connections, sending and receiving data either in String
or ArrayBuffer
format. This allows apps to act as both clients and servers, exposing connections over localhost
within and between apps (although multi-tasking on KaiOS is quite limited). Uses cases include:
- Sending and retrieving emails over POP or IMAP
- Chatting via an IRC client
- Transferring files over FTP
- Issuing direct DNS queries, instead of DNS over HTTPS (DoH)
Creating a local HTTP server also allows applications to serve up content requested by image, audio, and video elements, similar to a ServiceWorker
but without limitations. Of course this comes with the added complexity of writing your own HTTP server, and for multimedia requests also requires handling Range
requests.
Note: There is also a sibling UDPSocket
API for UDP socket connections, accessible via the
udp-socket
permission.
Let’s Encrypt SSL Certificate Issue
Let’s Encrypt (LE) is an open certificate authority (CA) that issues free SSL certificates, allowing websites to serve content over HTTPS. LE is so popular that it has issued more than one billion certificates. SSL certificates are important for many reasons, and in 2023 they are effectively required to avoid visitors seeing scary warning messages stating, “This Connection is Untrusted.”
In September 2021, the IdenTrust DST Root CA X3 root certificate used by Let’s Encrypt expired. For most internet users, this was a non-event because modern web-enabled devices include new root certificates with regular updates. However, most budget mobile phones including KaiOS devices do not receive regular over-the-air (OTA) updates. That means that as of the time of writing, most phones running KaiOS 2.5 will flag Let’s Encrypt SSL certificates as insecure.
As a developer, this means that XMLHttpRequest and Fetch requests to hosts using LE certificates will silently fail with no catchable error. Fortunately, while XHR does not expose the necessary error messages, it is possible to detect invalid SSL Certificates on KaiOS using mozTCPSocket
. The function below returns a Promise
that resolves to true
when the SecurityCertificate
is thrown.
1// @returns [Promise<Boolean|null>] True if the host has an invalid SSL certificate
2function isInvalidCertificate(host, timeout = 1000) {
3 // API not available, either not KaiOS or missing permission
4 if (!navigator.mozTCPSocket) {
5 return Promise.resolve(null);
6 }
7
8 return new Promise((resolve) => {
9 let timeoutId;
10 let isResolved = false;
11 const socket = navigator.mozTCPSocket
12 .open(host, 443, { useSecureTransport: true });
13
14 // Closes socket, if open, and resolves Promise
15 const closeAndResolve = (event) => {
16 if (socket.readyState !== 'closed') {
17 try {
18 socket.close();
19 } catch (e) {
20 console.warn(e);
21 }
22 }
23
24 // Handle SSL Certificate Scenario
25 if (event.type === 'error') {
26 if (event.name === 'SecurityError' && event.message === 'SecurityCertificate') {
27 isResolved = true;
28 clearTimeout(timeoutId);
29 return resolve(true); // True = Invalid
30 }
31 }
32
33 isResolved = true;
34 clearTimeout(timeoutId);
35 return resolve(false); // False = Valid
36 };
37
38 // Set socket timeout
39 timeoutId = setTimeout(() => {
40 if (!isResolved) {
41 closeAndResolve(false);
42 }
43 }, timeout);
44
45 socket.addEventListener('data', closeAndResolve);
46 socket.addEventListener('error', closeAndResolve);
47 });
48}
As expected, isInvalidCertificate
resolves true for anchor.fm
which uses a Let’s Encrypt SSL Certificate, and resolves false for google.com
which uses a certificate issued by Google Trust Services.
Tip: in Firefox if you click the lock icon then the arrow under “Connection secure,” you can see SSL certificate details.
Conclusion
KaiOS offers a variety of APIs to make external requests like a native app, including XHR and Fetch without CORS, as well as TCP and UDP Socket connections. All required permissions are only available to packaged Privileged applications, but enable your application to use third-party APIs, services, and protocols without running into Content Security Policy issues.
If you find these nuances daunting and need support developing tightly-integrated experiences on KaiOS, contact the author from the About page.