pimoroni / phew

MIT License
198 stars 42 forks source link

Add example of captive portal setup #4

Open lowfatcode opened 2 years ago

xuyunzeng commented 1 year ago

This might help. Limitations, notes and instructions, see PiCockpit tutorial.

from phew import logging, server, access_point, dns
from phew.template import render_template
from phew.server import redirect

DOMAIN = "pico.wireless"  # This is the address that is shown on the Captive Portal

@server.route("/", methods=['GET'])
def index(request):
    """ Render the Index page"""
    if request.method == 'GET':
        logging.debug("Get request")
        return render_template("index.html")

# microsoft windows redirects
@server.route("/ncsi.txt", methods=["GET"])
def hotspot(request):
    print(request)
    print("ncsi.txt")
    return "", 200

@server.route("/connecttest.txt", methods=["GET"])
def hotspot(request):
    print(request)
    print("connecttest.txt")
    return "", 200

@server.route("/redirect", methods=["GET"])
def hotspot(request):
    print(request)
    print("****************ms redir*********************")
    return redirect(f"http://{DOMAIN}/", 302)

# android redirects
@server.route("/generate_204", methods=["GET"])
def hotspot(request):
    print(request)
    print("******generate_204********")
    return redirect(f"http://{DOMAIN}/", 302)

# apple redir
@server.route("/hotspot-detect.html", methods=["GET"])
def hotspot(request):
    print(request)
    """ Redirect to the Index Page """
    return render_template("index.html")

@server.catchall()
def catch_all(request):
    print("***************CATCHALL***********************\n" + str(request))
    return redirect("http://" + DOMAIN + "/")

# Set to Accesspoint mode
# Change this to whatever Wifi SSID you wish
ap = access_point("Pico W Captive")
ip = ap.ifconfig()[0]
# Grab the IP address and store it
logging.info(f"starting DNS server on {ip}")
# # Catch all requests and reroute them
dns.run_catchall(ip)
server.run()                            # Run the server
logging.info("Webserver Started")

Forked from https://github.com/kevinmcaleer/cyberdog

simonprickett commented 1 year ago

Not sure if it's helpful but I made an example that exposes an captive AP then asks the user to supply their wifi credentials and saves those, then reboots and connects to their wifi, returning to the captive AP if the connection couldn't be made (e.g. because the SSID supplied can't be seen or the password supplied was incorrect) https://github.com/simonprickett/phewap

Nikorasu commented 1 year ago

This might help. Limitations, notes and instructions, see PiCockpit tutorial.

from phew import logging, server, access_point, dns
from phew.template import render_template
from phew.server import redirect

DOMAIN = "pico.wireless"  # This is the address that is shown on the Captive Portal

@server.route("/", methods=['GET'])
def index(request):
    """ Render the Index page"""
    if request.method == 'GET':
        logging.debug("Get request")
        return render_template("index.html")

# microsoft windows redirects
@server.route("/ncsi.txt", methods=["GET"])
def hotspot(request):
    print(request)
    print("ncsi.txt")
    return "", 200

@server.route("/connecttest.txt", methods=["GET"])
def hotspot(request):
    print(request)
    print("connecttest.txt")
    return "", 200

@server.route("/redirect", methods=["GET"])
def hotspot(request):
    print(request)
    print("****************ms redir*********************")
    return redirect(f"http://{DOMAIN}/", 302)

# android redirects
@server.route("/generate_204", methods=["GET"])
def hotspot(request):
    print(request)
    print("******generate_204********")
    return redirect(f"http://{DOMAIN}/", 302)

# apple redir
@server.route("/hotspot-detect.html", methods=["GET"])
def hotspot(request):
    print(request)
    """ Redirect to the Index Page """
    return render_template("index.html")

@server.catchall()
def catch_all(request):
    print("***************CATCHALL***********************\n" + str(request))
    return redirect("http://" + DOMAIN + "/")

# Set to Accesspoint mode
# Change this to whatever Wifi SSID you wish
ap = access_point("Pico W Captive")
ip = ap.ifconfig()[0]
# Grab the IP address and store it
logging.info(f"starting DNS server on {ip}")
# # Catch all requests and reroute them
dns.run_catchall(ip)
server.run()                            # Run the server
logging.info("Webserver Started")

Forked from https://github.com/kevinmcaleer/cyberdog

I'm having an odd issue with that. My old Nexus 7 (android 4) can connect to that AP, and even gets sent the "sign in to wifi" to direct me to the right page, no errors.. However when I try to connect using my Samsung phone (android 6), I get an error, and no notification or popup. (I can manually access the pages tho.)

Soon as my phone connects, I get this error on my Pico:

Task exception wasn't retrieved
future: <Task> coro= <generator object '_handle_request' at 2001a420>
Traceback (most recent call last):
  File "uasyncio/core.py", line 1, in run_until_complete
  File "phew/server.py", line 242, in _handle_request
  File "phew/server.py", line 161, in _parse_headers
ValueError: need more than 1 values to unpack

Anyone know how I can get it working with the Android 6 devices?

EDIT: I went to line 161 in server.py, and had it print(header_line) to see why name, value = header_line.decode().strip().split(": ", 1) was having trouble with my phone's request.. This is what prints right before the error:

2021-01-01 00:03:04 [info     / 161kB] > starting catch all dns server on port 53
2021-01-01 00:03:04 [info     / 158kB] > starting web server on port 80
b'Host: cdn.bandwidthx.net\r\n'
b'Connection: keep-alive\r\n'
b'Cache-Control: max-age=0\r\n'
b'Accept: text/plain,text/html,*/*\r\n'
b'Accept-Encoding: identity\r\n'
b'Accept-Language: en-US\r\n'
b'User-Agent: Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36; Bx/2.12.29.377.20190128\r\n'
b'Cookie: \r\n'
Task exception wasn't retrieved
future: <Task> coro= <generator object '_handle_request' at 2001a1e0>
Traceback (most recent call last):
  File "uasyncio/core.py", line 1, in run_until_complete
  File "phew/server.py", line 243, in _handle_request
  File "phew/server.py", line 162, in _parse_headers
ValueError: need more than 1 values to unpack

Starting to think it's just my lousy old phone, sending a bad requests.. My other devices work fine. lol

xuyunzeng commented 1 year ago

Android 6 might be pinging for a response from an endpoint that isn't set up to respond. My code is meant for newer devices.

According to this page, Android 6 would be seeking a response from connectivitycheck.gstatic.com

Nikorasu commented 1 year ago

Android 6 might be pinging for a response from an endpoint that isn't set up to respond. My code is meant for newer devices.

According to this page, Android 6 would be seeking a response from connectivitycheck.gstatic.com

Thanks for the link, tho for some reason, even if I add a check for that address, our weird old phones still cause that error. Regardless tho, it works great on pretty much everything else I've tested, so no worries.