Baileys icon indicating copy to clipboard operation
Baileys copied to clipboard

Native mobile api

Open SamuelScheit opened this issue 1 year ago • 7 comments

SamuelScheit avatar Apr 20 '23 11:04 SamuelScheit

I'll push the work i did for Whatsapp4j when I come back from my holidays. Then we should probably add support for registering business accounts. Also we need to fetch the token dynamically, because updating manually every time doesn't look like a good idea

Auties00 avatar Apr 22 '23 12:04 Auties00

So I found this code to be responsible for the token generation:

public final class C64833Bq {
    public static final byte[] A00 = Base64.decode("PkTwKSZqUfAUyR0rPQ8hYJ0wNsQQ3dW1+3SCnyTXIfEAxxS75FwkDf47wNv/c8pP3p0GXKR6OOQmhyERwx74fw1RYSU10I4r1gyBVDbRJ40pidjM41G1I1oN", 0);

    public static String A00(Context context, String str) {
        int i;
        byte[] bytes;
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        String packageName = context.getPackageName();
        if (packageName != null && "com.whatsapp".equals(packageName)) {
            try {
                String str2 = C01D.A09;
                byteArrayOutputStream.write(packageName.getBytes(str2));
                InputStream resourceAsStream = C64833Bq.class.getResourceAsStream("/res/drawable-hdpi/about_logo.png");
                if (resourceAsStream == null) {
                    resourceAsStream = C64833Bq.class.getResourceAsStream("/res/drawable-hdpi-v4/about_logo.png");
                }
                if (resourceAsStream == null) {
                    resourceAsStream = C64833Bq.class.getResourceAsStream("/res/drawable-xxhdpi-v4/about_logo.png");
                }
                if (resourceAsStream == null) {
                    Resources resources = context.getResources();
                    DisplayMetrics displayMetrics = new DisplayMetrics();
                    displayMetrics.setToDefaults();
                    displayMetrics.density = 1.5f;
                    displayMetrics.densityDpi = 240;
                    displayMetrics.scaledDensity = 1.5f;
                    float f = 240;
                    displayMetrics.xdpi = f;
                    displayMetrics.ydpi = f;
                    resourceAsStream = new Resources(resources.getAssets(), displayMetrics, resources.getConfiguration()).openRawResource(R.drawable.about_logo);
                }
                if (resourceAsStream != null) {
                    byte[] bArr = new byte[DefaultCrypto.BUFFER_SIZE];
                    try {
                        try {
                            int read = resourceAsStream.read(bArr);
                            while (true) {
                                if (read != -1) {
                                    byteArrayOutputStream.write(bArr, 0, read);
                                    read = resourceAsStream.read(bArr);
                                } else {
                                    try {
                                        break;
                                    } catch (IOException unused) {
                                    }
                                }
                            }
                            SecretKey A08 = C009501g.A08(byteArrayOutputStream.toByteArray(), A00, 128, 512);
                            A08.getEncoded();
                            try {
                                Mac mac = Mac.getInstance("HMACSHA1");
                                try {
                                    mac.init(A08);
                                    Signature[] A03 = C01B.A03(context);
                                    if (A03 != null && (r1 = A03.length) != 0) {
                                        for (Signature signature : A03) {
                                            mac.update(signature.toByteArray());
                                        }
                                        try {
                                            ZipFile zipFile = new ZipFile(context.getPackageCodePath());
                                            InputStream inputStream = zipFile.getInputStream(zipFile.getEntry("classes.dex"));
                                            try {
                                                MessageDigest messageDigest = MessageDigest.getInstance("MD5");
                                                byte[] bArr2 = new byte[DefaultCrypto.BUFFER_SIZE];
                                                while (true) {
                                                    int read2 = inputStream.read(bArr2);
                                                    if (read2 <= 0) {
                                                        break;
                                                    }
                                                    messageDigest.update(bArr2, 0, read2);
                                                }
                                                bytes = messageDigest.digest();
                                                inputStream.close();
                                                zipFile.close();
                                            } catch (Throwable th) {
                                                if (inputStream != null) {
                                                    try {
                                                        inputStream.close();
                                                    } catch (Throwable unused2) {
                                                    }
                                                }
                                                throw th;
                                            }
                                        } catch (Exception e) {
                                            Log.m15e("app/md5/bytes/error ", e);
                                            try {
                                                bytes = "null".getBytes(str2);
                                            } catch (UnsupportedEncodingException e2) {
                                                throw new Error(e2);
                                            }
                                        }
                                        mac.update(bytes);
                                        try {
                                            mac.update(str.getBytes(str2));
                                            return Base64.encodeToString(mac.doFinal(), 2);
                                        } catch (UnsupportedEncodingException e3) {
                                            throw new AssertionError(e3);
                                        }
                                    }
                                    throw new AssertionError();
                                } catch (InvalidKeyException e4) {
                                    throw new AssertionError(e4);
                                }
                            } catch (NoSuchAlgorithmException e5) {
                                throw new AssertionError(e5);
                            }
                        } finally {
                            try {
                                resourceAsStream.close();
                            } catch (IOException unused3) {
                            }
                        }
                    } catch (IOException unused4) {
                        throw new AssertionError();
                    }
                }
                throw new AssertionError();
            } catch (IOException e6) {
                throw new Error(e6);
            }
        }
        throw new AssertionError();
    }
}

Yet it doesn't seem to work. (This is for the android token) Any suggestions?

Auties00 avatar Apr 26 '23 19:04 Auties00

Do you mean this token here? What's your problem? Скриншот 30-04-2023 014156

salykingleb avatar Apr 29 '23 22:04 salykingleb

@Auties00 I've unified web/mobile to always use the tcp socket. I've tested it and it everything still works as expected

SamuelScheit avatar Apr 30 '23 10:04 SamuelScheit

Good. I also successfully implemented token generation for Android: https://github.com/Auties00/Whatsapp4j/blob/master/src/main/java/it/auties/whatsapp/util/TokenHelper.java I haven't been able to do it for IOS, but this should be good enough

Auties00 avatar May 01 '23 19:05 Auties00

Amazing work Samuel and Auties!

For some reason I don't have an approve button on this PR, no idea what's going on 😅

Auties just as a note since it's a lot of commits with some back and forth: once we merge, should we do it as a squash merge to keep the commit history a bit more comprehensible?

burstfreeze avatar May 04 '23 20:05 burstfreeze

@SamuelScheit i've tested your branch after unifying the mobile and web implementation and incoming messages stopped working in mobile socket. On the previous version they were working almost correctly

ripreal avatar May 06 '23 07:05 ripreal

@ripreal Messages were received, but the event was not emitted, because the app state keys weren't initialized (which aren't available on mobile). I've fixed the problem, by skipping app state key handling for mobile. Please test it again

SamuelScheit avatar May 14 '23 15:05 SamuelScheit

@SamuelScheit I've tested it. Now it is working!

ripreal avatar May 15 '23 20:05 ripreal

@SamuelScheit I noticed that in mobile socket updateProfileName method not working though in desktop version everything is ok. By default user name after registration has ugly ~ mark. It would be very helpful to find a way to change that. I guess in mobile name changing is totally different from desktop

ripreal avatar May 15 '23 20:05 ripreal

@SamuelScheit could you fix the conficts?

edgardmessias avatar May 18 '23 20:05 edgardmessias

Thanks for your contribution.

The next step is to wait for review and approval to merge it to main repository

The community can help reacting with a thumb up (:thumbsup:) for approval and rocket (:rocket:) for who has tested it.

To test this PR you can run the following command below:

# NPM
npm install @whiskeysockets/baileys@SamuelScheit/Baileys#master
# YARN v2
yarn add @whiskeysockets/baileys@SamuelScheit/Baileys#master

edgardmessias avatar May 23 '23 11:05 edgardmessias

@SamuelScheit , Can I release this resource this weekend? There something to do before merging?

edgardmessias avatar May 26 '23 11:05 edgardmessias

We need to add documentation to the Readme how to use the mobile api, but other than that it is finished.

SamuelScheit avatar May 26 '23 11:05 SamuelScheit

@SamuelScheit , all right, I think we can put a really basic documentation in the README.md and create a new section about the native API here: https://github.com/WhiskeySockets/whiskeysockets.github.io

edgardmessias avatar May 26 '23 11:05 edgardmessias

The documentation URL: https://whiskeysockets.github.io/docs/intro

edgardmessias avatar May 26 '23 11:05 edgardmessias

So we tested it with our Bot - Project.

Almost everything works perfectly - except setting profile-stuff etc ( cuz it calls app-patch void & causes exceptions )

but everything else works fine.

If this & 2FA Auth is implemented, its 100% to go ♥

Kuroosh avatar May 27 '23 23:05 Kuroosh

I need to fix the release workflow to release a new version

edgardmessias avatar Jun 06 '23 14:06 edgardmessias

How can be solved updateProfile Name and Picture without the app state keys?.

And also, can the mobile version used as Whatsapp Business?.

jleal52 avatar Jun 07 '23 04:06 jleal52

Released at https://github.com/WhiskeySockets/Baileys/releases/tag/v6.2.0

edgardmessias avatar Jun 07 '23 11:06 edgardmessias