Skip to content

Commit ea508af

Browse files
committed
Update scripts for new API
1 parent bb77de7 commit ea508af

File tree

2 files changed

+132
-50
lines changed

2 files changed

+132
-50
lines changed

purge/deactivate_all_users.py

Lines changed: 90 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,139 @@
11
#!/usr/bin/env python3
22

3-
from slackclient import SlackClient
4-
import requests
53
import time
4+
import sys
5+
6+
from slack_sdk import WebClient
7+
from slack_sdk.errors import SlackApiError
8+
import requests
69

710
# Taken here : https://api.slack.com/custom-integrations/legacy-tokens
8-
SLACK_TOKEN = ""
11+
SLACK_TOKEN = "xoxb-..."
912

1013
# Available in the HTML source code of https://[team].slack.com/admin
11-
WEB_SLACK_TOKEN = ""
14+
WEB_SLACK_TOKEN = "xoxs-..."
1215

1316
# Channel containing the members we want to deactivate
14-
DEST_CHANNEL = "general"
17+
DEST_CHANNEL = "FILL ME IN"
1518

1619
# Team Slack domain
1720
SLACK_DOMAIN = "opentoallctf.slack.com"
1821

22+
# Users we won't ban even if they are in the channel
23+
safe_user_names = {
24+
"7feilee",
25+
"Kroz",
26+
"Diis",
27+
"r00k",
28+
"Ariana",
29+
"Lord_Idiot",
30+
"UnblvR",
31+
"an0n",
32+
"drtychai",
33+
"enio",
34+
"eriner",
35+
"fevral",
36+
"grazfather",
37+
"idr0p",
38+
"kileak",
39+
"mementomori",
40+
"rh0gue",
41+
"sae",
42+
"sferrini",
43+
"uafio",
44+
"vakzz",
45+
"viva",
46+
"waywardsun",
47+
}
48+
1949
def channel_id_by_name(client, name):
20-
""" Fetch channel ID for a given channel name. """
50+
"""Fetch channel ID for a given channel name."""
51+
limit = 1000
52+
cursor = None
53+
while True:
54+
resp = client.conversations_list(types="public_channel", limit=limit, cursor=cursor)
55+
channels = resp["channels"]
2156

22-
output = client.api_call("channels.list")
23-
channels = output['channels']
57+
for channel in channels:
58+
if channel["name"] == name:
59+
return channel["id"]
2460

25-
channel_id = ''
26-
for channel in channels:
27-
if channel['name'] == name:
28-
return channel['id']
61+
cursor = resp["response_metadata"]["next_cursor"]
62+
if not cursor:
63+
break
2964

3065
return None
3166

67+
3268
def get_all_users(client):
33-
""" Fetch all users in the team. Includes deleted/deactivated users. """
69+
"""Fetch all users in the team. Includes deleted/deactivated users."""
70+
resp = client.users_list()
71+
return resp["members"]
3472

35-
output = client.api_call("users.list")
36-
return output['members']
3773

38-
sc = SlackClient(SLACK_TOKEN)
74+
def get_all_users_in_channel(client, channel_id):
75+
limit = 1000
76+
cursor = None
77+
members = []
78+
while True:
79+
resp = sc.conversations_members(channel=channel_id, limit=1000, cursor=cursor)
80+
cursor = resp["response_metadata"]["next_cursor"]
81+
members += resp["members"]
82+
if not cursor:
83+
break
84+
85+
return members
86+
87+
sc = WebClient(SLACK_TOKEN)
3988

4089
channel_id = channel_id_by_name(sc, DEST_CHANNEL)
4190

4291
if not channel_id:
4392
print("[!] No channel ID found for channel '{}'.".format(DEST_CHANNEL))
93+
sys.exit(1)
4494

4595
print("[*] Found channel {} ({}).".format(DEST_CHANNEL, channel_id))
4696

4797
# Get all members
4898
members = get_all_users(sc)
49-
members = dict([(member['id'], member) for member in members])
99+
members = {member["id"]: member for member in members}
100+
print("[*] Found {} total members.".format(len(members)))
50101

51102
# Get members in channel
52-
output = sc.api_call("channels.info", channel=channel_id)
53-
members_in_channel = output['channel']['members']
103+
members_in_channel = get_all_users_in_channel(sc, channel_id)
104+
print("[*] Found {} members in {}".format(len(members_in_channel), DEST_CHANNEL))
105+
106+
# Get member ids of the safe list
107+
safe_member_ids = {m_id for m_id, member in members.items() if member["name"] in safe_user_names}
108+
print("[*] Found {} blessed users".format(len(safe_member_ids)))
54109

55110
# Filter out bots and deactivated users.
56-
members_to_deactivate = []
57-
for member_id in members_in_channel:
58-
is_deactivated = members[member_id]['deleted']
59-
is_bot = members[member_id]['is_bot']
111+
doomed_members = []
112+
113+
doomed_members = [m_id for m_id in members_in_channel if
114+
not members[m_id]["deleted"] and not members[m_id]["is_bot"]
115+
and not m_id in safe_member_ids]
60116

61-
if not is_deactivated and not is_bot:
62-
members_to_deactivate.append(member_id)
117+
print("[*] Found {} doomed members".format(len(doomed_members)))
63118

64119
# Deactivate members.
65120
# Member deactivation through the slack API is only available for premium teams.
66121
# We can bypass this restriction by using a different API endpoint.
67122
# The code below simulates an admin manually deactivating users through the
68123
# ... web interface.
69-
print("[*] Deactivating {} members.".format(len(members_to_deactivate)))
124+
print("[*] Deactivating {} members.".format(len(doomed_members)))
70125
deactivate_url = "https://{}/api/users.admin.setInactive".format(SLACK_DOMAIN)
71-
for member_id in members_to_deactivate:
126+
for member_id in doomed_members:
72127

73-
username = members[member_id]['profile']['display_name']
74-
data = { "user" : member_id, "token": WEB_SLACK_TOKEN }
75-
headers = { "Content-Type" : "application/x-www-form-urlencoded" }
128+
username = members[member_id]["profile"]["display_name"]
129+
data = {"user": member_id, "token": WEB_SLACK_TOKEN}
130+
headers = {"Content-Type" : "application/x-www-form-urlencoded"}
76131
response = requests.post(deactivate_url, data=data, headers=headers)
77132

78-
print("[*] Kicking {} : {}".format(repr(username), member_id))
133+
print("[*] Banning {} ({})".format(username, member_id))
79134
print(response.text)
135+
if response.json().get("error") == "ratelimited":
136+
time.sleep(1)
80137

81-
# Prevent Slack's rate limiting
82-
time.sleep(1)
138+
# Avoid Slack's rate limiting
139+
time.sleep(0.5)

purge/invite_all_users.py

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,74 @@
11
#!/usr/bin/env python3
22

3-
from slackclient import SlackClient
3+
import time
4+
import sys
5+
6+
from slack_sdk import WebClient
7+
from slack_sdk.errors import SlackApiError
48

59
# Slack API Token
6-
SLACK_TOKEN = ""
10+
SLACK_TOKEN = "xoxb-..."
711

812
# Channel to invite users too
9-
DEST_CHANNEL = "general"
13+
DEST_CHANNEL = "FILL ME IN"
1014

1115
def channel_id_by_name(client, name):
12-
""" Fetch channel ID for a given channel name. """
16+
"""Fetch channel ID for a given channel name."""
17+
limit = 1000
18+
cursor = None
19+
while True:
20+
resp = client.conversations_list(types="public_channel", limit=limit, cursor=cursor)
21+
channels = resp["channels"]
1322

14-
output = client.api_call("channels.list")
15-
channels = output['channels']
23+
for channel in channels:
24+
if channel["name"] == name:
25+
return channel["id"]
1626

17-
channel_id = ''
18-
for channel in channels:
19-
if channel['name'] == name:
20-
return channel['id']
27+
cursor = resp["response_metadata"]["next_cursor"]
28+
if not cursor:
29+
break
2130

2231
return None
2332

24-
def get_all_users(client):
25-
""" Fetch all users in the team. Includes deleted/deactivated users. """
2633

27-
output = client.api_call("users.list")
28-
return output['members']
34+
def get_all_users(client):
35+
"""Fetch all users in the team. Includes deleted/deactivated users."""
36+
resp = client.users_list()
37+
return resp["members"]
2938

30-
sc = SlackClient(SLACK_TOKEN)
39+
sc = WebClient(SLACK_TOKEN)
3140

3241
channel_id = channel_id_by_name(sc, DEST_CHANNEL)
3342

3443
if not channel_id:
3544
print("[!] No channel ID found for channel '{}'.".format(DEST_CHANNEL))
45+
sys.exit(1)
3646

3747
print("[*] Found channel {} ({}).".format(DEST_CHANNEL, channel_id))
3848

3949
members = get_all_users(sc)
4050
print("[*] Found {} members.".format(len(members)))
4151

52+
# Join the channel, so we can invite to it
53+
sc.conversations_join(channel=channel_id)
54+
4255
# Invite to channel in groups of 30
4356
# Slack limits channel invitations to 30 members per API call.
4457
print("[*] Inviting users.")
45-
member_ids = [member['id'] for member in members]
58+
member_ids = [member["id"] for member in members]
4659
groups = [member_ids[n:n+30] for n in range(0, len(member_ids), 30)]
4760

4861
for group in groups:
49-
sc.api_call("conversations.invite", channel=channel_id, users=','.join(group))
62+
try:
63+
sc.conversations_invite(channel=channel_id, users=",".join(group))
64+
except SlackApiError as e:
65+
# Technically we can have up to 30 errors, and some might be bad
66+
# e.response.data["errors"] to check them individually
67+
if "ratelimited" in str(e):
68+
time.sleep(1)
69+
elif "cant_invite_self" in str(e):
70+
continue
71+
elif "already_in_channel" in str(e):
72+
continue
73+
# TODO: Should we bail otherwise?
74+
continue

0 commit comments

Comments
 (0)