Giter VIP home page Giter VIP logo

j-rios / tlg_joincaptchabot Goto Github PK

View Code? Open in Web Editor NEW
518.0 28.0 217.0 6.99 MB

Telegram Bot to verify if users joining a group are human. The Bot sends an image captcha for each new user and kicks any of them who can't solve the captcha in a specified time.

License: GNU General Public License v3.0

Python 95.15% Dockerfile 0.99% Makefile 0.46% Shell 3.40%
captcha bot telegram telegram-bot python python3 python-telegram-bot hacktoberfest

tlg_joincaptchabot's Introduction

TLG_JoinCaptchaBot

Telegram Bot to verify if a new member joining a group is a human. Upon a new user join a group, the Bot send an image-based captcha challenge that must be solved to allow the user stay in the group. If the new user fails to solve the captcha within a set time limit, they are removed from the group. Additionally, any message from a new user that includes a URL prior to the completion of the captcha will be considered Spam and will be deleted.

Donate

Do you like this Bot? Buy me a coffee :)

Paypal:

https://www.paypal.me/josrios

Installation

Note: Use Python 3.6 or above to install and run the Bot, previous python version are unsupported.

To generate Captchas, the Bot uses multicolor_captcha_generator library, which uses Pillow to generate the images.

  1. Install Pillow prerequisites:

    sudo apt update
    sudo apt install -y libtiff5-dev libjpeg62-turbo-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk
  2. Get the project and install JoinCaptchaBot requirements:

    git clone https://github.com/J-Rios/TLG_JoinCaptchaBot
    cd TLG_JoinCaptchaBot
    python3 -m pip install -r requirements.txt
  3. Set Telegram Bot account Token (get it from @BotFather) in "src/settings.py" file:

    'TOKEN' : 'XXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'

Configuration

All Bot configurations can be done easily by modifying them in the "src/settings.json" file.

For more experienced users, you can use environment variables to setup all that properties (this is really useful for advance deployment when using Virtual Environments and/or Docker to isolate the Bot process execution).

Usage

To ease it usage in Linux, a Makefile is provided.

  • Check usage help information:

    make
  • Launch the Bot:

    make run
  • Check if the Bot is running:

    make status
  • Stop the Bot:

    make kill

Systemd service

For systemd based systems, you can setup the Bot as daemon service.

To do that, you need to create a new service description file for the Bot as follow:

[vim or nano] /etc/systemd/system/tlg_joincaptcha_bot.service

File content:

[Unit]
Description=Telegram Join Captcha Bot Daemon
Wants=network-online.target
After=network-online.target

[Service]
Type=forking
WorkingDirectory=/path/to/TLG_JoinCaptchaBot/src/
ExecStart=/path/to/TLG_JoinCaptchaBot/tools/run
ExecReload=/path/to/TLG_JoinCaptchaBot/tools/kill

[Install]
WantedBy=multi-user.target

Then, to add the new service into systemd, you should enable it:

systemctl enable --now tlg_joincaptcha_bot.service

Now, you can start the service (Bot) by:

systemctl start tlg_joincaptcha_bot.service

You can check if the service (Bot) is running by:

systemctl status tlg_joincaptcha_bot.service

Remember that, if you wan't to disable it, you should execute:

systemctl disable tlg_joincaptcha_bot.service

Docker

You can also run the bot on Docker. This allows easy server migration and automates the installation and setup. Look at the docker specific documentation for more details about how to create a Docker Container for Captcha Bot.

Bot Owner

The Bot Owner can run special commands that no one else can use, like /allowgroup (if the Bot is private, this set allowed groups where the Bot can be used) or /allowuserlist (to make Bot don't ask for captcha to some users, useful for example for blind users).

You can setup a Bot Owner by specifying the Telegram User ID or Alias in "settings.py" file. For example:

"BOT_OWNER": "@JoseTLG",

Make Bot Private

By default, the Bot is Public, so any Telegram user can add and use the Bot in any group, but you can set it to be Private so the Bot just can be used in allowed groups (Bot owner allows them with /allow_group command).

You can set Bot to be Private in "settings.py" file:

"BOT_PRIVATE" : True,

Note: If you have a Public Bot and set it to Private, it will leave any group where is not allowed to be used when a new user joins.

Note: Telegram Private Groups could changes their chat ID when it become a public super-group, so the Bot will leave the group and the owner has to set the new group chat ID with /allow_group.

Scalability (Polling or Webhook)

By default, Bot checks and receives updates from Telegram Servers by Polling (it periodically requests and gets from Telegram Server if there is any new updates in the Bot account corresponding to that Bot Token), this is really simple and can be used for low to median scale Bots. However, you can configure the Bot to use Webhook instead if you expect to handle a large number of users/groups (with webhook, the Telegram Server is the one that will connect to you machine and send updates to the Bot when there is any new update).

To use Webhook instead Polling, you need a signed certificate file in the system, you can create the key file and self-sign the cert through openssl tool:

openssl req -newkey rsa:2048 -sha256 -nodes -keyout private.key -x509 -days 3650 -out cert.pem

Once you have the key and cert files, setup the next lines in "settings.py" file to point to expected host system address, port, path and certificate files:

"WEBHOOK_IP": "0.0.0.0",
"WEBHOOK_PORT": 8443,
"WEBHOOK_PATH": "/TLG_JoinCaptchaBot"
"WEBHOOK_CERT" : SCRIPT_PATH + "/cert.pem",
"WEBHOOK_CERT_PRIV_KEY" : SCRIPT_PATH + "/private.key",

(Optional) In case you want to use a reverse proxy between Telegram Server and the system that runs the Bot, you need to setup the Proxy Webhook URL setting:

"WEBHOOK_URL": "https://example.com:8443/TLG_JoinCaptchaBot"

Then, you need to change Bot connection mode from polling to webhook by setting to True the next configuration:

"CAPTCHABOT_USE_WEBHOOK": True,

To go back and use Polling instead Webhook, just set the config back to False:

"CAPTCHABOT_USE_WEBHOOK": False,

Adding a New Language

Actual language support is based on external JSON files that contain all bot texts for each language.

To add support for a new language you must follow this steps:

  1. Fork the project repository, clone it and create a new branch to work on it (i.e. named language-support-en).

  2. Copy from one of the existing language JSON files from here to a new one.

  3. Change the name of that file for the language ISO Code of the language that you want.

  4. Translate each text from JSON key values of the file without breaking the JSON format/structure (it should be valid for JSON parsers) and maintaining JSON key names. Keep command names in english (i.e. don't translate "START", "HELP"... /start /help ...) and don't remove special characters (like {}, ", ', \n...) too!

  5. Make a pull request of that branch with the new language file into this repository and wait for it to be accepted.

  6. Then, I will make the integration into source code and actual Bot account (@join_captcha_bot).

  7. Enjoy the new language :)

Languages Contributors

tlg_joincaptchabot's People

Contributors

2dreamy avatar anon97945 avatar antikruk avatar breakdowns avatar categulario avatar dakeshi avatar damascene avatar danygee avatar dependabot[bot] avatar isalvadoraz avatar j-rios avatar jprando avatar kopykata avatar kuvam avatar leixet avatar lelabtv avatar makyurt avatar marcopaganini avatar mikaela avatar nidamanx avatar rffontenelle avatar romangalimow avatar sajjad-021 avatar stezkoy avatar tonejito avatar toxi22 avatar vlab97 avatar weerdenburg avatar xa2er avatar zufardhiyaulhaq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tlg_joincaptchabot's Issues

[Request] Delete all messages from new users

How to delete all messages from new users?
There are bots that immediately reset the ad when it enters.
Can I get the bot to quickly delete all messages from a user who didn't pass the captcha?

[Bug] Bot unrestrict already banned users when kicking

I was banning some spam bot account before (because i administrating multiple group, so i know which one) they responding the captcha
image

but everytime the join captcha bot banned the spammy bot account, it always add their permission back
image

which is counter-productive

[Request] Delete any message sent by user if it's not solving the captcha

It would be nice to "mute" (delete all from) the new member until the captcha is solved.

For this, just delete any message that's not a solution to the captcha, and if it's a solution, then proceed accordingly.

It would also be good to choose whether to mute or kick (or even ban) users who don't solve captcha in the given time.

[Question] Fail to delete spam in Bot instance deployed?

I noticed new variance of spam message coming to my group

sample message and bot response
bot_tele_fail

and bot fail to delete message
bot_tele_fail_2

i want to contribute, but i dont know how to fix it, i have check your source code,

its around here https://github.com/J-Rios/TLG_JoinCaptchaBot/blob/master/sources/join_captcha_bot.py#L324

and i have check https://github.com/J-Rios/TLG_JoinCaptchaBot/blob/master/sources/tlds-alpha-by-domain.txt too,

but still doesnt have idea how to solve it, because python isnt my primary programming language

[Bug] Spammer learnt, now they use forwarding

Spammers have evolved, and now they forward messages from their own channels without passing the captcha.

Bot should block any message from the user until it resolves the captcha.

[Request] LANG_CHANGE message modification suggestion

in language file,

"LANG_CHANGE": "Language changed to English.",

With this constant message structure, a bot tells us misleading result when we configure it with other lang.

expected result

Language changed to {target_lang}

current result

Language changed to English

[Request] Restrict new users to send media

Hey,
im running into an issue with the bot and cant figure out why.
When a new user is coming to the group the user got the captcha from the bot. After he write in the right captcha the entry to the group is done. But here im getting the issue. When i then looking at the right for the new user the bot has restricted the rights so that the user cant share pics or something else. The admin must always switch the rights so the new users can share pics or other stuff. What am i missing?? Bot is running as admin and i just updated to the latest version of the JoinCaptchaBot. Is there some new config i do not know about or missing??

[Question] Delete Messages behavior

The /help and /commands say that only images sent are automatically deleted by the bot, no muting or other restrictions are put on a new unverified user since the bot does the message deleting automatically.

  1. Does the bot delete those images instantly, or is there a delay?

  2. Can it be set to delete ALL non-text messages, including gifs, videos, and stickers, or is that already implemented and just not stated anywhere?

Thank you

[Question] Docker pull

Hallo, what am i missing??

sudo docker pull captcha-bot
Using default tag: latest
Error response from daemon: pull access denied for captcha-bot, repository does not exist or may require 'docker login': denied: requested access to the resource is denied

[Request] Please send all messages silently

Telegram recently introduced the concept of silent messages. Nobody in a group wants to be bothered by captcha processes of new users. You could also ask the new user to send the catcha silent so users in the group are not getting annoyed by joining users.

Thank you this bot is really useful 👍

Persian language json file unsupported

The provided Persian language support file "fa.json" has an invalid format or is incompatible to actual json parser library. Due this, it cannot be use and has been disabled.

Some others minors errors:

  • There is some strange Latin characters, so it seems some translated texts parts are bad.
  • Some commands names in the texts has been translated, they must be reverted to english, commands don't need to be translated (/start /help /commands...).

[Request] Don't request solve captcha to invited users

Hi there @J-Rios, we've started using your Bot within a couple Telegram groups and it seems to work fine.

We were wondering if it's possible to skip the captcha for users invited by current group members.

I haven't ever coded a Telegram bot, but I have experience with Python, so if you can provide some directions, I could try to help.

If you are more comfortable speaking spanish, you can send me a priv.

Thanks in advance and congratulations for your work!

[Request] Delay before sending captcha

When a user joins a group with "Show history for new members" disabled, the bot is sometimes too quick to send the captcha, such that it isn't even visible to the new user.

This is most probably a bug on Telegram's side, but it would be useful to add a delay (~2-5 seconds) between recieving the event from telegram and sending a captcha.

Thanks for the great bot!

[Request] Configurable deletion of welcome messages

The captcha message is correctly being deleted, but the "Welcome" message that is sent after the confirmation succeeds is not. Looking at the source (http://bit.ly/2YICmuf) it appears that there's a call to tlg_send_selfdestruct_msg() to do this, but it's commented out. This should be an option, hidden behind configuration.

[Help] No Captcha when Join in own Bot instance

I install your program in Ubuntu and run successfully
The problem was, whenever I join my group using my different telegram account.
There is no Captcha appear.
What missing in my steps
tq

STEPS:
open telegram
search for BotFather and open
/newboot YOURbot
bot name YOURbot
username YOURbot
open YOURbot
/captcha_mode ascii

open Ubuntu

apt-get install libtiff5-dev libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms2-dev libwebp-dev tcl8.6-dev tk8.6-dev python-tk

git clone --recurse-submodules https://github.com/J-Rios/TLG_JoinCaptchaBot

pip install -r TLG_JoinCaptchaBot/requirements.txt

cd TLG_JoinCaptchaBot/sources

vi constants.py

modify this and put your token
Change "TOKEN" : "XXXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

./run

./status

Running (PID - 18171).
open your telegram group and add YOURbot as member and promote it as admin

[Request] Configure Bot group settings through private chat (similar to @MissRose_bot's functionality)

@MissRose_bot has the feature to connect remotely to the desired group to manage the bot's settings. Being linked to the group, you can send and get commands by calling them privately, once it's connected to the group you need to do the alterations and management.

I'm currently using @join_captcha_bot because Rose lacks more features as yours have. And will probably keep it this way for some time since it suits my needs.

You can connect to the group remotely with the /connect command.

Example:
/connect -1001235155926

Which -1001235155926 is the group !id.

Could that be possible?

Or you could integrate with Rose, by any chance... If that's even possible.

Thanks!

[Question] Own Bot instance deployment failure (ImportError: cannot import name 'MessageEntity' from 'telegram')

Hello,

I'm trying to create a Docker for TLG_JoinCaptchaBot. I've followed all instructions on the README.md (with the change of changing libjpeg8 to libjpeg62-turbo, as libjpeg8 is not available on Debian). I've installed the requirements with pip3 (Debian's python3 version of pip). When I try to run the bot, I get:

Traceback (most recent call last):
  File "join_captcha_bot.py", line 34, in <module>
    from telegram import MessageEntity, ParseMode, InputMediaPhoto,  InlineKeyboardButton, \
ImportError: cannot import name 'MessageEntity' from 'telegram' (/usr/local/lib/python3.7/dist-packages/telegram/__init__.py)

Running python3 by hand and attempting to import the library above gives me the same result, as expected.

The curious thing is that I don't see this module under the "telegram" library. Any ideas?

[Notice] Update languages

About:

  • The Bot support multiples languages through JSON files.
  • When a new Bot functionality is added to Bot code it could needs to create new texts messages and sometimes the contributor didn't add that texts in all languages.

Requesting:

  • Take a look into languages files and compare them to English texts file to add/translate missing texts in each language.

Notes:

  • English language file is the default language and should contains all the last texts needed from the project. So the english file can be used to compare, update and translate the other languages files according to it.
  • This is a persistent issue and shouldn't be closed due any new functionality can bring new missing language text translations again. Let's just keep it to notify the world about it.

[Request] Use @username in captcha message

If user has a @username, use that in the message that says to do the captcha. In that way the new user gets a notification, knows she must do something. Now, a user can join a group just before lunch, then does not see this bot's message.

[Question] Hide messages notifications

Hallo, is it possible to add a command so that the admin/admins will not become the CaptchaBot message??
Somthing like "do not send to ChatID xxxxxx
You can get your ChatID at @FalconGate_Bot
But i guess you know that ;)

Best
Tim

[Question] How to run with Docker and environment variables?

Hello,

i´m trying to run the docker instance with other "environment variable" but it will not work for me.

docker run -d --name captcha-bot --env CAPTCHABOT_TOKEN="xxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxx" --env CAPTCHABOT_OWNER="xxxxxxxx" --env CAPTCHABOT_INIT_LANG="DE" --restart always captcha-bot

The container is running, but not with language=DE. It always starts with language=EN

Whats my problem??

[Request] Inherit markdown formatting from original message on /welcome_msg set-up

I noticed that the welcome message won't be set up as the same formatting as we format in the normal markdown form.

The break lines, underscores, bold, italic, etc, won't be inherited to the normal formatting.

Probably what you have in mind with the welcome message is something brief, but detailing more for lay people that barely understand how Telegram works would be a bit better.

I've set it up along with Rose to explain what should be done, after all there are many people that join Telegram to ask a few things and drop out right after some days or weeks.

Can that be done?

Expected behavior:

image

Current behavior:

image

Thanks.

[Question] Bot Private Mode usage

Hello @J-Rios !

I've saw that you've included an option to change bot mode for private.
I've tried to include more than one group and it looks it doesnt worked!

Would be possible to modify to add group with nickname @groupName instead group id?

[Request] Mute new users for a few minutes/hours

Hello!

First of all, thanks for the bot. Terribly useful.

Second, an idea: Would it be too difficult to mute new users for a few minutes/hours? Frequently people don't bother reading the group rules (or even the captcha message!), and a bit of a "cool off" time when they join may be the incentive to behave.

[Request] Make bot private to certain groups only

I would like to host the bot for several groups that I manage and would like to have the bot only responding or can be added to a certain group only.

This StackOverflow post have hint to how to control the bot: https://stackoverflow.com/questions/46015319/how-to-make-a-private-telegram-bot-accessible-only-by-its-owner

If you can help show where the bot determines the channel it joins, I can try to figure out how to limit the bot. Or someone else with better Python expertise can help as well

Thank you.

[Bug] Docker build Bot fails if INIT_LANG is set to an invalid value

Setting CONST.INIT_LANG to an invalid value prevents the Bot from initializing properly, without any relevant error messages logged. The bot will run, but not respond to any commands.

This is a particularly easy hole to fall in, since the /language command expects the language to be specified in lowercase (E.g, "en") but for CONFIG.INIT_LANG, the language needs to be specified in upper case (E.g. "EN"). A simple case mismatch is enough to trigger the problem.

[Help] Users with non-ascii characters can't be banned?

Hi...

A long time ago, I was using the bot version: Current Bot version: 1.10.4 (06/22/2020) and lately some Russian bots have started to enter, in which it is not possible to mark them to ban. When understanding, Telegram allows you to create accounts without a user profile, so you can't ban them via 'inline'. The problem with this, is that the Russians in particular use crazy characters, and that you can't ban them. In this version, when they enter, at least it shows the "user account", as an example:

2021-02-27 20:53:55: [-00_removed_00] New join detected: Денис Будахян (1674530619)
2021-02-27 20:53:55: [-00_removed_00] Sending captcha message to Денис Будахян: E2DD ...
2021-02-27 20:53:56: [-00_removed_00] Captcha send process complete.

2021-02-27 20:54:56: [-00_removed_00] Captcha reply timed out for user Денис Будахян.
2021-02-27 20:54:56: [-00_removed_00] Captcha not solved, kicking Денис Будахян (1674530619) ...
2021-02-27 20:54:57: [-00_removed_00] Increased join_retries to 5
2021-02-27 20:54:58: [-00_removed_00] Removing messages from user Денис Будахян ...
2021-02-27 20:54:58: [-00_removed_00] Kick / Ban process complete

So, to ban this bot, I need to type: tg: // user? Id = 1674530619

I thought, that this problem had been solved in the Current Bot version: 1.18.0 (02/27/2021)

However, the result was a bot crash, as follows:

2021-02-27 21:49:39: Bot started.
2021-02-27 21:49:39: File /TLG_JoinCaptchaBot/sources/data/allowedusers.txt not found, creating it ...
2021-02-27 21:49:39: File /TLG_JoinCaptchaBot/sources/data/bannedgroups.txt not found, creating it ...
2021-02-27 21:49:39: Resources initialized.
2021-02-27 21:49:39: Setup Bot for Polling.
2021-02-27 21:49:40: Bot setup completed. Bot is now running.
2021-02-27 21:55:09: [-00_removed_00] Scheduled deletion time for message: 27663
2021-02-27 21:55:09: [-00_removed_00] Message to delete not found
2021-02-27 21:55:10: [-00_removed_00] Scheduled deletion time for message: 27664

2021-02-27 18: 57: 47,533 - telegram.utils.promise - ERROR - An uncaught error was raised while running the promise
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/telegram/utils/promise.py", line 56, in run
self._result = self.pooled_function (* self.args, ** self.kwargs)
File "join_captcha_bot.py", line 536, in new_member_join
printts ("[{}] New join detected: {} ({})". format (chat_id, join_user_name, join_user_id))
File "/TLG_JoinCaptchaBot/sources/commons.py", line 67, in printts
print ("{}: {}". format (actual_date, to_print))
UnicodeEncodeError: 'ascii' codec can't encode characters in position 57-61: ordinal not in range (128)
2021-02-27 21:58:06: [-00_removed_00] Scheduled deletion time for message: 27667
2021-02-27 21:58:06: [-00_removed_00] Message to delete not found
2021-02-27 21:58:07: [-00_removed_00] Scheduled deletion time for message: 27668
2021-02-27 21:58:07: [-00_removed_00] Message to delete not found

2021-02-27 18: 58: 09,963 - telegram.utils.promise - ERROR - An uncaught error was raised while running the promise
Traceback (most recent call last):
File "/usr/local/lib/python3.6/dist-packages/telegram/utils/promise.py", line 56, in run
self._result = self.pooled_function (* self.args, ** self.kwargs)
File "join_captcha_bot.py", line 536, in new_member_join
printts ("[{}] New join detected: {} ({})". format (chat_id, join_user_name, join_user_id))
File "/TLG_JoinCaptchaBot/sources/commons.py", line 67, in printts
print ("{}: {}". format (actual_date, to_print))
UnicodeEncodeError: 'ascii' codec can't encode character '\ u200e' in position 57: ordinal not in range (128)
2021-02-27 21:58:10: [-00_removed_00] Scheduled deletion time for message: 27669
2021-02-27 21:58:10: [-00_removed_00] Message to delete not found
2021-02-27 21:58:10: [-00_removed_00] Scheduled deletion time for message: 27670
2021-02-27 21:58:10: [-00_removed_00] Message to delete not found
^ C

The first error occurred when this user entered (without quotes): "Илья токсичая жител_ка постмодерниз_ма!"

The second error, with this user (without quotes): "Elena ♥ ️97"

How can I fix this problem?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.