Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration w/ Soupcan #139

Closed
bethylamine opened this issue Jun 20, 2023 · 23 comments · Fixed by bethylamine/soupcan#72
Closed

Integration w/ Soupcan #139

bethylamine opened this issue Jun 20, 2023 · 23 comments · Fixed by bethylamine/soupcan#72
Labels
enhancement New feature or request

Comments

@bethylamine
Copy link

Some users of Soupcan (transphobe-highlighting extension) have requested an auto-block feature, i.e.: bethylamine/soupcan#45

This would function very similar to Blue Blocker except with different criteria. Wondering if it's possible to do something like add an option to Block transphobes if they have Soupcan installed. Saves me having to reinvent the great blocking code you have here and also adds extra functionality to BB.

https://github.com/bethylamine/soupcan

@kheina
Copy link
Collaborator

kheina commented Jun 20, 2023

believe it or not, this is my first browser extension. I'd really love to have integration with soupcan (I use it myself) as well as other extensions like twitter real verified, but quite frankly, I don't know how extensions can integrate with each other, but I'd love to work together to figure out a way to do so

@kheina kheina added the enhancement New feature or request label Jun 20, 2023
@kheina
Copy link
Collaborator

kheina commented Jun 20, 2023

we can use external messages to pass data between extensions: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessageExternal

I can set up an external message handler and restrict which extension ids to allow messages from to be only from yours. you can then send me messages containing user id, name, screen name (handle), and block purpose to be handled by my extension.

from your end it might look something like this:

browser.runtime.sendMessage(
	"{119be3f3-597c-4f6a-9caf-627ee431d374}",  // firefox extension id
	{ action: "BLOCK", user_id: "1234567890", name: "transphobe", screen_name: "tr4nsph0be", reason: "X reports of transphobia" },
	{ ...options },
)

reason is used to output logs to the console in the format: [Blue Blocker] blocked {name} (@{screen_name}) due to {reason}.

@bethylamine
Copy link
Author

Yeah, I think that could work. Is there a way Soupcan could detect that BlueBlocker is enabled and running? e.g. adding a .blue-blocker-active class to the body tag of the Twitter page?

@bethylamine
Copy link
Author

bethylamine commented Jun 24, 2023

Also, Soupcan only identifies transphobes by screen_name / it doesn't hijack the XHR requests to get API data like BB does. We might need to meet in the middle somehow on that one, especially if I were to have Soupcan block high-profile transphobes from a database list first rather than just on-sight. But I can also supplement that list with user IDs and names, I think.

Added a page context menu item to send a test message in v0.10.12. Unsure what ID you'll get from the sender if you load it unpacked, but I've also sent them for publishing to the Chrome/FF stores.

https://github.com/bethylamine/soupcan/blob/main/manifest-v3/background.js#L120-L136

2023-06-23 20_17_05-(14) Home _ Twitter

@kheina
Copy link
Collaborator

kheina commented Jun 24, 2023

so, I was actually thinking about this the other day, re: userids. but about installation detection I'll mention here first:

you should be able to do this from the management api: https://developer.chrome.com/docs/extensions/reference/management/#method-get

chrome.management.get("jgpjphkbfjhlbajmmcoknjjppoamhpmm").then(e => console.log(e));
Promise {<pending>}
{
    "description": "Blocks all Twitter Blue verified users on twitter.com",
    "disabledReason": "unknown",
    "enabled": false,
    "homepageUrl": "https://chrome.google.com/webstore/detail/jgpjphkbfjhlbajmmcoknjjppoamhpmm",
    "hostPermissions": [],
    "icons": [
        {
            "size": 128,
            "url": "chrome://extension-icon/jgpjphkbfjhlbajmmcoknjjppoamhpmm/128/0"
        }
    ],
    "id": "jgpjphkbfjhlbajmmcoknjjppoamhpmm",
    "installType": "normal",
    "isApp": false,
    "mayDisable": true,
    "mayEnable": true,
    "name": "Blue Blocker",
    "offlineEnabled": false,
    "optionsUrl": "",
    "permissions": [
        "storage"
    ],
    "shortName": "Blue Blocker",
    "type": "extension",
    "updateUrl": "https://clients2.google.com/service/update2/crx",
    "version": "0.2.7"
}

though, you'll need to add management to your permissions in your manifest

@bethylamine
Copy link
Author

Looks good. It seems like for unpacked extensions, the ID is generated based on the absolute path of the extension (at least in Chrome.)

image

@kheina
Copy link
Collaborator

kheina commented Jun 24, 2023

so, I was thinking about this earlier and figured that it worked off of urls like shinigami eyes does. unfortunately, it doesn't look like the rest id is really available anywhere in the dom except on the userpage itself and idk what kind of html parsing/editing you do besides the color changing, so that probably wouldn't work either.

you also need the user id to do a follow or block request, which means blue blocker would need to do another request to fetch the user id of any handle you send, which I really don't want to do, just because more requests the extension makes the more likely it gets detected, the more likely the user gets banned, etc.

we could use this endpoint, which is the one that gets made when a user hovers over a name and it gets extra info, which is probably the most lenient from twitter's perspective, but we would still need to be careful about how often something gets sent.

https://twitter.com/i/api/1.1/friends/following/list.json?include_profile_interstitial_type=1&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&include_ext_has_nft_avatar=1&include_ext_is_blue_verified=1&include_ext_verified_type=1&include_ext_profile_image_shape=1&skip_status=1&cursor=-1&user_id=1455273288&count=3&with_total_count=true

@kheina
Copy link
Collaborator

kheina commented Jun 24, 2023

Looks good. It seems like for unpacked extensions, the ID is generated based on the absolute path of the extension (at least in Chrome.)

so, the absolute path of the extension is the extension id, and it gets assigned when you publish an extension on the chrome webstore, so that jgpjphkbfjhlbajmmcoknjjppoamhpmm value shouldn't change. firefox is similar where it assigns a value, but it also has a value that's stored in the manifest, but for blue blocker, that's {119be3f3-597c-4f6a-9caf-627ee431d374} (WITH the braces, annoyingly)

@bethylamine
Copy link
Author

bethylamine commented Jun 24, 2023

so, I was thinking about this earlier and figured that it worked off of urls like shinigami eyes does. unfortunately, it doesn't look like the rest id is really available anywhere in the dom except on the userpage itself and idk what kind of html parsing/editing you do besides the color changing, so that probably wouldn't work either.

you also need the user id to do a follow or block request, which means blue blocker would need to do another request to fetch the user id of any handle you send, which I really don't want to do, just because more requests the extension makes the more likely it gets detected, the more likely the user gets banned, etc.

we could use this endpoint, which is the one that gets made when a user hovers over a name and it gets extra info, which is probably the most lenient from twitter's perspective, but we would still need to be careful about how often something gets sent.

The other alternative is for BlueBlocker to query by screen name when it runs through its list of candidates. Soupcan can return true or false if it's a hit, and BlueBlocker can take it from there. Having the "BLOCK" external message is good too, though, since IMO there is an 80-20 rule of transphobes which is 80% of transphobic content is shared by 20% of the transphobic accounts, so by blocking those first, the net gain would be realized quicker. Upon enabling blocking, Soupcan could check the latest DB for the top transphobes and send the screen name + user ID to BlueBlocker. Since this curated list would be processed offline, the user IDs can be scraped server side rather than client side.

But starting with injecting an extra condition into "is blue, is NFT, ... is transphobe" seems natural

@kheina
Copy link
Collaborator

kheina commented Jun 24, 2023

that could certainly work, I could have external messages open on name + screen_name + id and then also send screen names to soupcan for verification, but that would be a lot of requests. just from the ui messages, I assume the db is replicated locally, so that could work.

@bethylamine
Copy link
Author

I think DB lookup is probably one of the fastest parts of the Soupcan extension lol, yup, it's just a hashmap lookup. If message requests are a concern, BB could also just request the hashmap itself and do everything internally.

@kheina
Copy link
Collaborator

kheina commented Jun 24, 2023

nah, I'm not concerned about that, I'm just saying if it were making an api request. I have no concerns for the efficiency of messaging handling lol

@kheina
Copy link
Collaborator

kheina commented Jun 24, 2023

here's what I've got mocked up. the payloads and fingerprints of everything will, of course, be up to you, but I would highly recommend having some sort of action or function key so that you can have multiple kinds of messages or versioning in the future

if you return more data than just status or true/false like number of reports or etc, I can add options for those as well

chrome.runtime.sendMessage(
	SoupcanExtensionId,
	{ action: "check_twitter_user", screen_name: user.legacy.screen_name },
).then(response => {
	// TODO: add following, etc checks here
	if (response?.status === "transphobic") {
		queueBlockUser(user, String(user.rest_id), ReasonNftAvatar);
	}
});

@kheina
Copy link
Collaborator

kheina commented Jun 24, 2023

ps is there a soupcan logo usable somewhere from your extension? I'd like to place the logo the "enable soupcan integration" option
nvm I don't think you can use it outside the extension context anyway

@bethylamine
Copy link
Author

Feel free to use the icons from the Soupcan repository e.g. https://github.com/bethylamine/soupcan/blob/main/manifest-v3/icon400.png

@bethylamine
Copy link
Author

Seems promising!

image

@bethylamine
Copy link
Author

bethylamine/soupcan@e2a98ef includes the receiving end.

@kheina
Copy link
Collaborator

kheina commented Jun 24, 2023

image
looks pretty good!

@kheina
Copy link
Collaborator

kheina commented Jun 25, 2023

sharing this with you because I just spent a long time figuring out why this doesn't work. turns out, when you define your onMessage listener as async, you have issues returning a value if you ever use await

to fix this, you need to first define a synchronous listener func which then calls an async func and finally returns true.

basically, this works:

api.runtime.onMessageExternal.addListener((m, s, r) => { (async (message, sender, respond) => {
	await something();
	respond({ ...response });
})(m, s, r); return true });

but this doesn't

api.runtime.onMessageExternal.addListener(async (_message, sender, respond) => {
	await something();
	respond({ ...response });  // always returns undefined
});

@kheina
Copy link
Collaborator

kheina commented Jun 26, 2023

integration isn't working on firefox on bethylamine/soupcan@e2a98ef because of Uncaught ReferenceError: importScripts is not defined in your background script. I'm not sure what would be causing that, though, everything I've found says it should work fine

@bethylamine
Copy link
Author

bethylamine commented Jun 29, 2023

Try the latest version, I think this has since been fixed, by using different ways of importing these files in chrome/firefox. Firefox does it through the manifest and Chrome imports it with importScripts

https://github.com/bethylamine/soupcan/blob/main/manifest-v3/background.js#L220-L223

@kheina
Copy link
Collaborator

kheina commented Jun 29, 2023

Try the latest version, I think this has since been fixed, by using different ways of importing these files in chrome/firefox. Firefox does it through the manifest and Chrome imports it with importScripts

https://github.com/bethylamine/soupcan/blob/main/manifest-v3/background.js#L220-L223

thanks! this makes it a lot easier to do development on firefox. I wasn't aware of importing files via the manifest.

your external message listener still has the async issue I described here, though. I made a fix for it in my pr here

also, Blue Blocker now fires a test message to check if the extension exists or not, so you should be able to tell if Blue Blocker is able to communicate with soupcan just by opening the context menu and seeing if the option if available in the advanced tab.

ex: blue blocker v0.3.2 (live) on firefox and soupcan v0.11.7 (live)
Blue Blocker settings menu screenshot

ex: blue blocker v0.3.2 (live) on firefox and soupcan v0.11.7 (with async workaround)
Blue Blocker settings menu screenshot with soupcan visible

@cooljeanius
Copy link
Collaborator

Just FYI, there's a new PR open updating the Soupcan integration: #336.
If any Soupcan users could help review it, that'd be appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants