Skip to content

Instantly share code, notes, and snippets.

@chwnam
Last active May 3, 2024 02:10
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save chwnam/5b583ecb6bafa7f8b25de41827f3d510 to your computer and use it in GitHub Desktop.
Save chwnam/5b583ecb6bafa7f8b25de41827f3d510 to your computer and use it in GitHub Desktop.
스타벅스 와이파이 자동 인증 파이썬3 스크립트
#!/usr/bin/env python3
import time
from http.cookiejar import Cookie
from re import search, findall
from urllib.parse import urlencode
from urllib.request import (
HTTPCookieProcessor,
HTTPRedirectHandler,
Request,
build_opener
)
class RedirectionCheckHandler(HTTPRedirectHandler):
"""
302 리다이렉션이 일어났는지 점검하기 위한 핸들러
"""
def __init__(self):
self.code = ''
self.redirect_url = ''
def http_error_302(self, req, fp, code, msg, headers):
self.code = code
self.redirect_url = ''
return super().http_error_302(req, fp, code, msg, headers)
class KtStarbucksAutoAuthorize(object):
"""
KT 스타벅스에 자동으로 접속 인증합니다.
{"result_cd":"0000"} 이라는 응답이 들어오면 성공입니다.
"""
def __init__(self):
self.cooke_processor = HTTPCookieProcessor()
self.redirect_handler = RedirectionCheckHandler()
self.opener = build_opener(self.redirect_handler, self.cooke_processor)
def authorize(self):
"""
스타벅스 와이파이 네트워크에 인증 처리를 시도합니다.
"""
url = self.step1_check_captive_network()
if not url:
print("이미 인증 된 것 같은데요? 인터넷 잘 쓰세요!")
return
data = self.step2_post_form(url)
if not data:
print('스타벅스 지점을 못 찾았네요...')
return
print(self.step3_authorize(data))
def step1_check_captive_network(self):
"""
captive network 점검입니다. http 쪽으로 테스트를 해서 302 응답이 날아오는지 점검합니다.
"""
response = self.get_response('http://detectportal.firefox.com/success.txt')
if self.redirect_handler.code != 302:
return ''
html = response.read().decode('utf-8')
found = search('location.href = "(http://.+)";', html)
if not found:
return ''
return found.group(1)
def step2_post_form(self, url):
"""
step1 에서 302 리다이렉션의 주소로 접속을 시도합니다.
응답으로 아주 심플한 자바스크립트를 얻게 됩니다. 이 스크립트를 통해 재차 리다이렉션이 일어날 것을 기대하고 있습니다.
리다이렉션을 통해 접속한 URL 에서는 폼을 발견할 수 있습니다. 이 폼 양식을 POST 전송하게 되어 있습니다.
간단하게 HTML 홈 양식을 분석해 웹브라우저를 흉내냅니다.
"""
response = self.get_response(url)
html = response.read().decode('euc-kr')
# step3에 사용할 쿠키를 구워 둡니다. 스크립트와 정확히 동작하게 한다는 가정하에 작성하였으나,
# 테스트 결과 없어도 큰 문제는 없었습니다.
# cookie_found = findall('<script language="javascript">document.cookie="(.+?)";</script>', html)
# if cookie_found:
# for cookie in cookie_found:
# self.set_cookie(cookie, 'first.wifi.olleh.com')
form_found = findall('<input type="hidden" name="(.+?)" value="(.+?)">', html)
if not form_found:
return ''
data = {key: value for key, value in form_found}
self.get_response(
url='http://first.wifi.olleh.com/starbucks/index_en.html', # 폼이 전송될 곳은 정해져 있습니다.
data=data
)
return data
def step3_authorize(self, data):
"""
step2 에서 POST 전송을 보내면, 비로소 웹브라우저 화면과 유사한 사용자 동의 체크박스가 나오는 화면의 HTML 문서를 전달받습니다.
웹브라우저에서 사용자 동의 체크 박스가 나오는 화면입니다.
여기서 마지막으로 인증을 위한 POST 요청을 보내면 됩니다. 이 때 referer 필드는 중요합니다.
"""
print('data', data);
data = {
'firstflag': 'starbucks',
'branchflag': data['branchflag'] if 'branchflag' in data else '',
'lang': 'en',
'devicecode': 'pc',
'ip': data['ip'],
'secure_id': '',
'ssid': data['ssid'],
'mac': data['mac']
}
print('data', data)
response = self.get_response(
url='http://first.wifi.olleh.com/starbucks/auth_issue.php',
data=data,
referer='https://first.wifi.olleh.com/starbucks/index_kr.html'
)
return response.read().decode('utf-8').strip()
def get_response(self, url, data=None, referer=None):
if data:
data = urlencode(data).encode('utf-8')
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0',
'Accept': '*/*',
'Accept-Language': 'ko,en-US;q=0.7,en;q=0.3',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
}
if referer:
headers['Referer'] = referer
request = Request(
url=url,
data=data,
headers=headers
)
return self.opener.open(request)
def set_cookie(self, cookie_string, domain):
"""
쿠키를 굽습니다. 인증 과정에 있어 중요한 요소는 아닌 것 같지만, 가급적 웹브라우저의 요청/응답과 유사하게 하기 위해 구현해 두었습니다.
"""
params = {
"version": 0,
"name": '',
"value": '',
"port": None,
"port_specified": False,
"domain": '',
"domain_specified": False,
"domain_initial_dot": False,
"path": '/',
"path_specified": True,
"secure": False,
"expires": None,
"discard": True,
"comment": None,
"comment_url": None,
"rest": {},
"rfc2109": False
}
items = cookie_string.split(';')
key_val = items[0].split('=')
name = key_val[0].strip()
value = key_val[1].strip()
params['name'] = name
params['value'] = value
for item in items[1:]:
key_val = item.split('=')
key = key_val[0].strip()
val = key_val[1].strip()
params[key] = val
params['domain'] = domain
if params['expires']:
pattern = '%a, %d %b %Y %H:%M:%S %Z'
epoch = int(time.mktime(time.strptime(params['expires'], pattern)))
params['expires'] = epoch
self.cooke_processor.cookiejar.set_cookie(Cookie(**params))
if __name__ == '__main__':
KtStarbucksAutoAuthorize().authorize()
@chwnam
Copy link
Author

chwnam commented Jul 28, 2019

그리고 우분투 리눅스 데스크탑 사용시 스크립트를 덧붙입니다
이 스크립트는 네트워크를 접속했을 때 , SSID가 'kt_starbucks'이면 이 스크립트를 자동으로 실행하도록 합니다. 이제 더 이상 사용자 동의 화면을 거치지 않아도 스타벅스 와이파이를 사용할 수 있습니다.

/etc/network/if-up.d 경로에 다음 스크립트를 작성합니다.

#!/bin/bash
# /etc/network/if-up.d/kt_starbucks

SSID=$(iwgetid -r | tr '[:upper:]' '[:lower:]')
SCRIPT='/path/to/kt_starbucks.py' # 파이썬 스크립트의 경로를 입력해 두세요
LOG='/path/to/log' # 마지막 실행 결과를 기록해 둡니다.
USER='user' # 사용자의 계정을 입력해 두세요

if [[ ${SSID}=='kt_startbucks' && -x ${SCRIPT}  ]]; then
	sudo --user=${USER} ${SCRIPT} 2>&1 | tee ${LOG}
fi

@lifefeel
Copy link

lifefeel commented Sep 5, 2019

잘 쓰고 있습니다. Mac에서 인증창이 안 뜰때가 자주 있었는데, 이 스크립트로 인증 잘 통과합니다.

@chwnam
Copy link
Author

chwnam commented Mar 1, 2023

2023년에도 잘 동작한다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment