IG: support TOTP
This commit is contained in:
		
							parent
							
								
									350b611f1b
								
							
						
					
					
						commit
						befa92ed72
					
				
					 3 changed files with 98 additions and 3 deletions
				
			
		|  | @ -3,9 +3,10 @@ import logging | |||
| from typing import List | ||||
| 
 | ||||
| from instagrapi import Client | ||||
| import pyotp | ||||
| 
 | ||||
| from backend.utils import ld_picturemaker | ||||
| from config.config import DEBUG, ACCOUNT_USERNAME, ACCOUNT_PASSWORD | ||||
| from config.config import DEBUG, ACCOUNT_USERNAME, ACCOUNT_PASSWORD, _2FA | ||||
| from utils.err import easyExceptionHandler | ||||
| #from utils.const import DEVICE | ||||
| 
 | ||||
|  | @ -46,7 +47,15 @@ def login() -> int: | |||
|             old_session = cl.get_settings() | ||||
|             cl.set_settings({}) | ||||
|             cl.set_uuids(old_session["uuids"]) | ||||
|             cl.login(ACCOUNT_USERNAME, ACCOUNT_PASSWORD) | ||||
|              | ||||
|             if _2FA == "TOTP": | ||||
|                 from config.config import _2FA_TOTPSEED | ||||
|                 totp = pyotp.TOTP(_2FA_TOTPSEED) | ||||
|                 totpcode = totp.now() | ||||
|                 cl.login(ACCOUNT_USERNAME, ACCOUNT_PASSWORD, verification_code=totpcode) | ||||
|             else: | ||||
|                 cl.login(ACCOUNT_USERNAME, ACCOUNT_PASSWORD) | ||||
|              | ||||
|             cl.get_timeline_feed() | ||||
|         except: | ||||
|             iglog.error("Cannot log in") | ||||
|  |  | |||
|  | @ -30,6 +30,9 @@ RELOGIN_LIMIT = 10*60  # 10 mins - re-login limit | |||
| # IG | ||||
| ACCOUNT_USERNAME = "" | ||||
| ACCOUNT_PASSWORD = "" | ||||
| ## IG.2FA | ||||
| _2FA = "" # we only support totp now :P | ||||
| _2FA_TOTPSEED = "" | ||||
| 
 | ||||
| # type define {mine:ext} | ||||
| FILE_MINE_TYPE = { | ||||
|  | @ -48,7 +51,8 @@ FILE_MINE_TYPE = { | |||
| #################### | ||||
| # Interface config # | ||||
| #################### | ||||
| INTERFACE = "interface/example.py" | ||||
| #INTERFACE = "interface/example.py" | ||||
| INTERFACE = "interface/tcivs.py" | ||||
| 
 | ||||
| #################### | ||||
| #   PictureMaker   # | ||||
|  |  | |||
							
								
								
									
										82
									
								
								interface/tcivs.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								interface/tcivs.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,82 @@ | |||
| import datetime | ||||
| import requests | ||||
| import io | ||||
| 
 | ||||
| """ | ||||
| Interface | ||||
| 
 | ||||
| The bridge between web application(niming) and igapi. | ||||
| An interface should have a get() function. | ||||
| """ | ||||
| 
 | ||||
| HOST="http://172.16.20.145:3000" | ||||
| 
 | ||||
| def get(index:int, media:bool=True) -> dict | None: | ||||
|     """ | ||||
|     Every interface should have this function. | ||||
|     Backend calls this function to get data of a post. | ||||
|      | ||||
|     Args: | ||||
|         index (int): ID of the post | ||||
|         media (bool): Send media or not | ||||
|      | ||||
|     Returns: | ||||
|         dict: Data of a post. Formatted as shown in Note 1 (an_example_of_context) | ||||
|         None: An error occurred, and nothing was returned. | ||||
|     """ | ||||
|      | ||||
|     # get data | ||||
|     ## fake server in localhost | ||||
|     ### where is the api of web application? | ||||
|     res = requests.get(f"{HOST}/api/post?cursor={index}") | ||||
|     if res.status_code != 200: | ||||
|         return None | ||||
|      | ||||
|     rj = res.json()[0] | ||||
|     media_arr = [] | ||||
|      | ||||
|     # get media | ||||
|     if media and rj["enclosure"] is not None: | ||||
|         for m in rj["enclosure"]: | ||||
|             _m = requests.get(f"{HOST}/{m}") | ||||
|             if _m.status_code == 200: | ||||
|                 media_arr.append(io.BytesIO(_m.content)) | ||||
|      | ||||
|     # return | ||||
|     result = { | ||||
|         "id": rj["id"], | ||||
|         "metadata": { | ||||
|             "create_time": datetime.datetime.strptime(rj["post_at"], "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=datetime.timezone.utc), | ||||
|             "author": rj["signing"], | ||||
|             "tags": [], | ||||
|             "category": "", | ||||
|             # ext | ||||
|             "parent": None #rj["parent"] # parent id | ||||
|         }, | ||||
|         "content": { | ||||
|             "text": rj["content"], | ||||
|             "media": media_arr | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     return result | ||||
| 
 | ||||
| 
 | ||||
| # Note 1 | ||||
| an_example_of_context = { | ||||
|     "id": int, | ||||
|     "metadata": { | ||||
|         "create_time": datetime.datetime, | ||||
|         "author": str, | ||||
|         "tags": list[str], | ||||
|         "category": str, | ||||
|         # ext | ||||
|         "parent": int | None # parent id | ||||
|     }, | ||||
|     "content": { | ||||
|         "text": str, | ||||
|         "media": [ | ||||
|             io.BytesIO | ||||
|         ] | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		
		Reference in a new issue