Mobile app support
Hello,
do you think it would be possible to get the official app working with rmfakecloud?
I tried running strings on it's .apk and found it's not using the my.remarkable.com URL directly and it relies on tokens and cookies from the Web login.
I'm thinking of trying modifying the latest 3.20.x app version but I'm not sure it it's possible.
I've noticed that there's issue https://github.com/ddvk/rmfakecloud-proxy/issues/5 that might be somewhat related
It appears most of the Android apps logic is handled within shared libraries. These libraries do contain strings like [*].tectonic.remarkable.com, you probably have to patch those...
you can actually avoid needing to patch rm's libraries every version by modifying libQt6Network_arm64-v8a.so to override the default cert store. just build qt 6.8.2 for android using NDK v26.1.10909125, modify QSslSocketPrivate::setDefaultCaCertificates in qtbase/src/network/ssl/qsslsocket.cpp to load your custom ca, and replace libQt6Network_arm64-v8a.so with the version you just built and it should work with rmfakecloud just fine.
i've been doing this since v3.18 and it's also working fine in 3.20. (that being said, i haven't actually tested v3.20's login as i upgraded from 3.18)
you can actually avoid needing to patch rm's libraries every version by modifying
libQt6Network_arm64-v8a.soto override the default cert store. just build qt 6.8.2 for android using NDK v26.1.10909125, modifyQSslSocketPrivate::setDefaultCaCertificatesinqtbase/src/network/ssl/qsslsocket.cppto load your custom ca, and replacelibQt6Network_arm64-v8a.sowith the version you just built and it should work with rmfakecloud just fine. i've been doing this since v3.18 and it's also working fine in 3.20. (that being said, i haven't actually tested v3.20's login as i upgraded from 3.18)
This requires the proxy to be always running tho, right?
you can actually avoid needing to patch rm's libraries every version by modifying
libQt6Network_arm64-v8a.soto override the default cert store. just build qt 6.8.2 for android using NDK v26.1.10909125, modifyQSslSocketPrivate::setDefaultCaCertificatesinqtbase/src/network/ssl/qsslsocket.cppto load your custom ca, and replacelibQt6Network_arm64-v8a.sowith the version you just built and it should work with rmfakecloud just fine. i've been doing this since v3.18 and it's also working fine in 3.20. (that being said, i haven't actually tested v3.20's login as i upgraded from 3.18)
Thanks, I'll take a look on it and report back
This requires the proxy to be always running tho, right?
rmfakecloud needs to be always running. you'll also need to add dns records to point to rmfakecloud in your dns server. i don't personally use a proxy though. not sure how it'd affect your setup. (but i guess it needs to be running if you point the dns reconds to it)
I want to have a somewhat universal solution for this. I have a rooted phone, so changing DNS records wouldn't be an issue, but still
I want to have a somewhat universal solution for this. I have a rooted phone, so changing DNS records wouldn't be an issue, but still
not sure how hard would it be to modify qt's hostname resolution, but that could be a solution. i didn't look into it since i already had the custom records as part of my rmfakecloud setup. and you don't need a rooted phone. any custom/self-hosted dns server would work.
I'd love to be able to just replace all of the domain strings for mine instance. I think that would be the easiest method to do so.
If that's possible, I'd then try to automate that using some custom written tool so it's easier for others to use
@er-azh okay, I'm stuck at the login as I need to have a user token :/ I replaced the my.remarkable.com URL for mine (had to create another one to match the original length, otherwise the app's view got killed and only whitecreen stayed).
~~The problem is there's not callback in the rmfakecloud prepared for this - ie the my.domain.com/#mobile~~
Now, after changing the loginUrl, the Log in button opens the configured rmfake instance. However, after entering the code, the app gets stuck at this:
I'll try to fix this now
@er-azh could you please describe how did you make the app work? I'm not sure if I follow
@Joedmin you are most likely failing the tls handshake since your rmfakecloud server's cert is not trusted, either your libQt6Network modification didn't work or you didn't do it. you can potentially check it with a packet capture. see if any of your tls connections are ending prematurely with a tls alert. and again, i'd advise against modifying strings in the binaries. it's very fragile and will change every version.
as for my dns setup, i've created an A record for rmfakecloud.internal pointing to my rmfakecloud server and then i did:
hwr-production-dot-remarkable-production.appspot.com. IN CNAME rmfakecloud.internal.
service-manager-production-dot-remarkable-production.appspot.com. IN CNAME rmfakecloud.internal.
local.appspot.com. IN CNAME rmfakecloud.internal.
my.remarkable.com. IN CNAME rmfakecloud.internal.
ping.remarkable.com. IN CNAME rmfakecloud.internal.
internal.cloud.remarkable.com. IN CNAME rmfakecloud.internal.
backtrace-proxy.cloud.remarkable.engineering. IN CNAME rmfakecloud.internal.
dev.ping.remarkable.com. IN CNAME rmfakecloud.internal.
dev.tectonic.remarkable.com. IN CNAME rmfakecloud.internal.
dev.internal.cloud.remarkable.com. IN CNAME rmfakecloud.internal.
on my dns server.
i've already explained how to change libQt6Network to trust your rmfakecloud server's cert in https://github.com/ddvk/rmfakecloud/issues/381#issuecomment-32752313020.
and as for my modification, here's the exact change i made to qsslsocket.cpp (janky but it works):
void QSslSocketPrivate::setDefaultCaCertificates(const QList<QSslCertificate> &certs)
{
const char* customCaPemData = "-----BEGIN CERTIFICATE-----...my ca here...-----END CERTIFICATE-----\n";
QByteArray caCertData = customCaPemData;
QList<QSslCertificate> customCerts = QSslCertificate::fromData(caCertData, QSsl::Pem);
if (customCerts.isEmpty()) {
fprintf(stderr, "ca load failed!\n");
}
QSslSocketPrivate::ensureInitialized();
QMutexLocker locker(&globalData()->mutex);
globalData()->config.detach();
globalData()->config->caCertificates = customCerts;
globalData()->dtlsConfig.detach();
globalData()->dtlsConfig->caCertificates = certs;
// when the certificates are set explicitly, we do not want to
// load the system certificates on demand
s_loadRootCertsOnDemand = false;
}
and qsslconfiguration.cpp (not sure about this one. i didn't check since it worked and building qt is hell):
QList<QSslCertificate> QSslConfiguration::caCertificates() const
{
const char* customCaPemData = "-----BEGIN CERTIFICATE-----...my ca here...-----END CERTIFICATE-----\n";
QByteArray caCertData = customCaPemData;
QList<QSslCertificate> customCerts = QSslCertificate::fromData(caCertData, QSsl::Pem);
if (customCerts.isEmpty()) {
fprintf(stderr, "ca load failed!\n");
}
return customCerts;
}
if you want a general solution, you can probably make it read the ca from a file inside the apk, then distribute the compiled qt binaries with an apk builder that replaces the qt libs (that way you can avoid distributing any copyrighted material).
and if you still want to avoid the dns setup part, you should probably look into the way qt does hostname resolution (check qtbase/src/network/kernel/qhostinfo.cpp). and if all else fails, you can most likely override getaddrinfo.
also since my last comment, i've checked logging in to rmfakecloud with v3.20 too. it works fine.
@er-azh thanks for your comment, was wondering if this kind of hack is also doable for the window app since it's also QT based ?