0000: 23 21 2f 75 73 72 2f 62 69 6e 2f 70 68 70 2d 63 #!/usr/bin/php-c
0010: 67 69 20 2d 64 63 67 69 2e 66 6f 72 63 65 5f 72 gi -dcgi.force_r
0020: 65 64 69 72 65 63 74 3d 30 0a 3c 3f 70 68 70 0a edirect=0.<?php.
0030: 23 20 65 6e 63 6f 64 69 6e 67 3a 20 75 74 66 2d # encoding: utf-
0040: 38 0a 23 20 61 70 69 3a 20 63 67 69 0a 23 20 74 8.# api: cgi.# t
0050: 79 70 65 3a 20 61 75 74 68 0a 23 20 74 69 74 6c ype: auth.# titl
0060: 65 3a 20 49 6e 64 69 65 41 75 74 68 20 61 75 74 e: IndieAuth aut
0070: 68 6f 72 69 7a 61 74 69 6f 6e 5f 65 6e 64 70 6f horization_endpo
0080: 69 6e 74 0a 23 20 64 65 73 63 72 69 70 74 69 6f int.# descriptio
0090: 6e 3a 20 56 65 72 69 66 69 65 73 20 61 20 72 65 n: Verifies a re
00a0: 6d 6f 74 65 20 75 73 65 72 20 69 64 20 28 55 52 mote user id (UR
00b0: 4c 29 20 61 67 61 69 6e 73 74 20 61 63 74 69 76 L) against activ
00c0: 65 20 66 6f 73 73 69 6c 20 6c 6f 67 69 6e 0a 23 e fossil login.#
00d0: 20 76 65 72 73 69 6f 6e 3a 20 30 2e 35 0a 23 20 version: 0.5.#
00e0: 73 74 61 74 65 3a 20 61 6c 70 68 61 0a 23 20 64 state: alpha.# d
00f0: 65 70 65 6e 64 73 3a 20 70 68 70 3a 63 75 72 6c epends: php:curl
0100: 2c 20 70 68 70 3a 73 71 6c 69 74 65 0a 23 20 64 , php:sqlite.# d
0110: 6f 63 3a 20 68 74 74 70 73 3a 2f 2f 77 77 77 2e oc: https://www.
0120: 77 33 2e 6f 72 67 2f 54 52 2f 69 6e 64 69 65 61 w3.org/TR/indiea
0130: 75 74 68 2f 23 61 75 74 68 65 6e 74 69 63 61 74 uth/#authenticat
0140: 69 6f 6e 2c 0a 23 20 20 20 20 20 68 74 74 70 73 ion,.# https
0150: 3a 2f 2f 69 6e 64 69 65 77 65 62 2e 6f 72 67 2f ://indieweb.org/
0160: 61 75 74 68 6f 72 69 7a 61 74 69 6f 6e 2d 65 6e authorization-en
0170: 64 70 6f 69 6e 74 0a 23 20 63 6f 6e 66 69 67 3a dpoint.# config:
0180: 20 2d 0a 23 0a 23 20 4d 69 6e 69 6d 61 6c 20 69 -.#.# Minimal i
0190: 6d 70 6c 65 6d 65 6e 74 61 74 69 6f 6e 20 6f 66 mplementation of
01a0: 20 49 6e 64 69 65 41 75 74 68 20 6c 6f 67 69 6e IndieAuth login
01b0: 20 65 6e 64 70 6f 69 6e 74 2e 20 52 75 6e 73 20 endpoint. Runs
01c0: 61 73 20 66 6f 73 73 69 6c 20 63 67 69 0a 23 20 as fossil cgi.#
01d0: 65 78 74 65 6e 73 69 6f 6e 20 74 6f 20 76 65 72 extension to ver
01e0: 69 66 79 20 63 75 72 72 65 6e 74 6c 79 20 6c 6f ify currently lo
01f0: 67 67 65 64 20 69 6e 20 75 73 65 72 2e 20 43 6f gged in user. Co
0200: 6e 66 69 72 6d 73 20 49 6e 64 69 65 41 75 74 68 nfirms IndieAuth
0210: 2f 4f 41 75 74 68 0a 23 20 72 65 71 75 65 73 74 /OAuth.# request
0220: 2c 20 61 6e 64 20 6b 65 65 70 73 20 6c 6f 67 69 , and keeps logi
0230: 6e 20 74 6f 6b 65 6e 73 20 69 6e 20 60 66 78 5f n tokens in `fx_
0240: 61 75 74 68 60 20 74 61 62 6c 65 2e 0a 23 0a 23 auth` table..#.#
0250: 20 54 68 69 73 20 6d 69 67 68 74 20 70 72 6f 67 This might prog
0260: 72 65 73 73 20 69 6e 74 6f 20 61 20 2f 74 6f 6b ress into a /tok
0270: 65 6e 20 65 6e 64 70 6f 69 6e 74 2c 20 69 64 65 en endpoint, ide
0280: 61 6c 6c 79 20 65 6e 61 62 6c 69 6e 67 20 2f 6d ally enabling /m
0290: 69 63 72 6f 70 75 62 0a 23 20 66 6f 72 20 74 68 icropub.# for th
02a0: 65 20 74 69 63 6b 65 74 20 73 79 73 74 65 6d 20 e ticket system
02b0: 6c 61 74 65 72 20 6f 6e 2e 20 57 68 69 63 68 20 later on. Which
02c0: 69 73 20 77 68 79 20 74 68 65 20 66 78 5f 61 75 is why the fx_au
02d0: 74 68 2f 74 6f 6b 65 6e 20 74 61 62 6c 65 0a 23 th/token table.#
02e0: 20 69 73 20 73 6f 6d 65 77 68 61 74 20 6f 66 20 is somewhat of
02f0: 61 20 62 6c 6f 62 20 63 6f 6c 6c 65 63 74 69 6f a blob collectio
0300: 6e 20 69 6e 20 69 74 73 65 6c 66 2e 0a 23 0a 23 n in itself..#.#
0310: 0a 23 20 23 23 20 53 45 54 55 50 0a 23 0a 23 20 .# ## SETUP.#.#
0320: 53 6f 20 74 68 69 73 20 72 65 71 75 69 72 65 73 So this requires
0330: 20 69 6e 73 74 61 6c 6c 61 74 69 6f 6e 20 69 6e installation in
0340: 20 66 6f 73 73 69 6c 73 20 65 78 74 72 6f 6f 74 fossils extroot
0350: 3a 20 28 69 6e 74 65 72 6e 61 6c 20 63 67 69 20 : (internal cgi
0360: 73 63 72 69 70 74 73 29 2c 0a 23 20 61 6e 64 20 scripts),.# and
0370: 6d 69 67 68 74 20 6e 6f 74 20 77 6f 72 6b 20 69 might not work i
0380: 6e 20 63 68 72 6f 6f 74 20 6a 61 69 6c 73 20 28 n chroot jails (
0390: 64 75 65 20 74 6f 20 70 68 70 2d 63 67 69 20 73 due to php-cgi s
03a0: 68 65 62 61 6e 67 29 2e 20 43 6f 70 79 20 74 68 hebang). Copy th
03b0: 65 20 73 63 72 69 70 74 0a 23 20 69 6e 74 6f 20 e script.# into
03c0: 65 78 74 2f 2c 20 70 72 65 66 65 72 72 61 62 6c ext/, preferrabl
03d0: 79 20 77 69 74 68 6f 75 74 20 2e 70 68 70 20 6f y without .php o
03e0: 72 20 2e 63 67 69 20 65 78 74 65 6e 73 69 6f 6e r .cgi extension
03f0: 2c 20 61 6e 64 20 63 68 6d 6f 64 20 2b 78 20 69 , and chmod +x i
0400: 74 2e 0a 23 0a 23 20 49 66 20 69 6e 76 6f 6b 65 t..#.# If invoke
0410: 64 20 77 69 74 68 6f 75 74 20 61 6e 79 20 70 61 d without any pa
0420: 72 61 6d 65 74 65 72 73 2c 20 74 68 69 73 20 66 rameters, this f
0430: 6f 73 73 69 6c 2d 63 67 69 20 73 63 72 69 70 74 ossil-cgi script
0440: 20 77 69 6c 6c 20 69 6e 69 74 69 61 6c 69 7a 65 will initialize
0450: 0a 23 20 74 68 65 20 60 66 78 5f 61 75 74 68 60 .# the `fx_auth`
0460: 20 64 61 74 61 62 61 73 65 20 74 61 62 6c 65 2e database table.
0470: 0a 23 0a 23 20 55 73 65 72 20 61 63 63 6f 75 6e .#.# User accoun
0480: 74 73 20 61 72 65 20 72 65 71 75 69 72 65 64 20 ts are required
0490: 74 6f 20 6c 69 73 74 20 68 6f 6d 65 70 61 67 65 to list homepage
04a0: 73 20 69 6e 20 74 68 65 20 60 69 6e 66 6f 60 20 s in the `info`
04b0: 63 6f 6c 75 6d 6e 2e 20 45 61 63 68 0a 23 20 6e column. Each.# n
04c0: 65 65 64 73 20 61 74 20 6c 65 61 73 74 20 6f 6e eeds at least on
04d0: 65 2c 20 73 6f 20 72 65 71 75 65 73 74 73 20 63 e, so requests c
04e0: 61 6e 27 74 20 62 65 20 75 73 65 64 20 74 6f 20 an't be used to
04f0: 61 70 70 72 6f 76 65 20 61 72 62 69 74 72 61 72 approve arbitrar
0500: 79 20 75 72 6c 73 2e 0a 23 0a 23 20 41 66 74 65 y urls..#.# Afte
0510: 72 77 61 72 64 73 20 63 6f 6e 66 69 67 75 72 65 rwards configure
0520: 20 79 6f 75 72 20 68 6f 6d 65 70 61 67 65 20 74 your homepage t
0530: 6f 20 61 6c 6c 6f 77 20 69 74 73 20 75 73 65 20 o allow its use
0540: 61 73 20 49 6e 64 69 65 41 75 74 68 20 69 64 3a as IndieAuth id:
0550: 0a 23 20 3c 6c 69 6e 6b 20 72 65 6c 3d 61 75 74 .# <link rel=aut
0560: 68 6f 72 69 7a 61 74 69 6f 6e 5f 65 6e 64 70 6f horization_endpo
0570: 69 6e 74 20 68 72 65 66 3d 22 68 74 74 70 3a 2f int href="http:/
0580: 2f 66 6f 73 73 69 6c 2e 64 6f 6d 61 69 6e 2f 65 /fossil.domain/e
0590: 78 74 2f 61 75 74 68 2e 63 67 69 22 3e 0a 23 0a xt/auth.cgi">.#.
05a0: 23 0a 23 20 23 23 20 54 4f 4b 45 4e 0a 23 0a 23 #.# ## TOKEN.#.#
05b0: 20 54 68 65 20 66 78 5f 61 75 74 68 20 74 61 62 The fx_auth tab
05c0: 6c 65 20 63 6f 6e 74 61 69 6e 73 20 69 6e 64 69 le contains indi
05d0: 76 69 64 75 61 6c 20 63 6f 6c 75 6d 6e 73 20 6e vidual columns n
05e0: 6f 77 20 74 6f 20 72 65 63 6f 72 64 20 70 72 65 ow to record pre
05f0: 76 69 6f 75 73 0a 23 20 61 75 74 68 6f 72 69 7a vious.# authoriz
0600: 61 74 69 6f 6e 20 72 65 71 75 65 73 74 73 2e 0a ation requests..
0610: 23 20 4d 6f 73 74 20 6f 66 20 77 68 69 63 68 20 # Most of which
0620: 69 73 20 75 6e 6e 65 63 65 73 73 61 72 79 20 74 is unnecessary t
0630: 6f 20 6b 65 65 70 20 61 66 74 65 72 20 74 68 65 o keep after the
0640: 20 69 6e 69 74 69 61 6c 20 72 65 71 75 65 73 74 initial request
0650: 2e 20 54 68 69 73 20 69 73 0a 23 20 6c 61 72 67 . This is.# larg
0660: 65 6c 79 20 66 6f 72 20 64 65 62 75 67 67 69 6e ely for debuggin
0670: 67 2e 20 49 66 20 2f 74 6f 6b 65 6e 20 73 75 70 g. If /token sup
0680: 70 6f 72 74 20 67 65 74 73 20 69 6d 70 6c 65 6d port gets implem
0690: 65 6e 74 65 64 2c 20 69 74 20 6d 69 67 68 74 20 ented, it might
06a0: 65 69 74 68 65 72 0a 23 20 63 72 65 61 74 65 20 either.# create
06b0: 64 69 73 74 69 6e 63 74 20 63 6f 64 65 20 65 6e distinct code en
06c0: 74 72 69 65 73 2c 20 6f 72 20 6a 75 73 74 20 61 tries, or just a
06d0: 64 64 20 22 73 63 6f 70 65 22 3a 20 65 74 63 2e dd "scope": etc.
06e0: 20 74 6f 20 74 68 65 20 65 78 69 73 74 69 6e 67 to the existing
06f0: 0a 23 20 65 6e 74 72 69 65 73 20 2d 20 61 6e 64 .# entries - and
0700: 20 72 65 75 73 65 20 74 68 65 20 61 75 74 68 20 reuse the auth
0710: 6b 65 79 73 20 61 73 20 4f 41 75 74 68 20 42 65 keys as OAuth Be
0720: 61 72 65 72 20 74 6f 6b 65 6e 2e 0a 23 0a 23 0a arer token..#.#.
0730: 23 20 23 23 20 50 52 4f 54 4f 43 4f 4c 0a 23 0a # ## PROTOCOL.#.
0740: 23 20 41 75 74 68 6f 72 69 7a 61 74 69 6f 6e 20 # Authorization
0750: 72 65 71 75 65 73 74 3a 0a 23 20 20 20 20 3f 6d request:.# ?m
0760: 65 3d 68 74 74 70 73 3a 2f 2f 75 73 65 72 2e 65 e=https://user.e
0770: 78 61 6d 70 6c 65 2e 6f 72 67 2f 0a 23 20 20 20 xample.org/.#
0780: 20 26 63 6c 69 65 6e 74 5f 69 64 3d 68 74 74 70 &client_id=http
0790: 3a 2f 2f 61 70 70 2e 65 78 61 6d 70 6c 65 2e 63 ://app.example.c
07a0: 6f 6d 2f 0a 23 20 20 20 20 26 72 65 64 69 72 65 om/.# &redire
07b0: 63 74 5f 75 72 69 3d 68 74 74 70 3a 2f 2f 61 70 ct_uri=http://ap
07c0: 70 2e 65 78 61 6d 70 6c 65 2e 63 6f 6d 2f 6c 6f p.example.com/lo
07d0: 67 69 6e 2f 63 61 6c 6c 62 61 63 6b 0a 23 20 20 gin/callback.#
07e0: 20 20 26 73 74 61 74 65 3d 31 32 33 34 35 36 37 &state=1234567
07f0: 38 39 30 0a 23 20 20 20 20 26 72 65 73 70 6f 6e 890.# &respon
0800: 73 65 5f 74 79 70 65 3d 63 6f 64 65 0a 23 20 20 se_type=code.#
0810: 20 20 26 73 63 6f 70 65 3d 70 72 6f 66 69 6c 65 &scope=profile
0820: 2b 63 72 65 61 74 65 2b 75 70 64 61 74 65 2b 64 +create+update+d
0830: 65 6c 65 74 65 0a 23 20 20 20 20 26 63 6f 64 65 elete.# &code
0840: 5f 63 68 61 6c 6c 65 6e 67 65 3d 42 73 65 36 34 _challenge=Bse64
0850: 78 31 32 33 2e 2e 0a 23 20 20 20 20 26 63 6f 64 x123...# &cod
0860: 65 5f 63 68 61 6c 6c 65 6e 67 65 5f 6d 65 74 68 e_challenge_meth
0870: 6f 64 3d 53 32 35 36 0a 23 20 41 63 74 69 6f 6e od=S256.# Action
0880: 3a 0a 23 20 20 20 20 c2 b7 20 76 65 72 69 66 79 :.# ยท verify
0890: 20 75 73 65 72 20 65 78 69 73 74 73 2c 20 69 73 user exists, is
08a0: 20 6c 6f 67 67 65 64 20 69 6e 2c 20 61 6e 64 20 logged in, and
08b0: 6d 65 3d 20 70 61 72 61 6d 65 74 65 72 20 69 73 me= parameter is
08c0: 20 77 68 69 74 65 6c 69 73 74 65 64 0a 23 20 20 whitelisted.#
08d0: 20 20 c2 b7 20 63 6f 6e 66 69 72 6d 20 70 65 72 ยท confirm per
08e0: 20 62 75 74 74 6f 6e 20 70 72 65 73 73 2c 20 6f button press, o
08f0: 72 20 64 69 72 65 63 74 20 75 6e 61 75 74 68 65 r direct unauthe
0900: 6e 74 69 63 61 74 65 64 20 75 73 65 72 20 74 6f nticated user to
0910: 20 2f 6c 6f 67 69 6e 20 70 61 67 65 0a 23 20 20 /login page.#
0920: 20 20 c2 b7 20 67 65 6e 65 72 61 74 65 20 61 6e ยท generate an
0930: 20 61 72 62 69 74 72 61 72 79 20 63 6f 64 65 2c arbitrary code,
0940: 20 72 65 63 6f 72 64 20 69 6e 20 66 78 5f 61 75 record in fx_au
0950: 74 68 20 74 61 62 6c 65 2f 6a 73 6f 6e 20 62 6c th table/json bl
0960: 6f 62 0a 23 20 52 65 73 70 6f 6e 73 65 3a 0a 23 ob.# Response:.#
0970: 20 20 20 20 4c 6f 63 61 74 69 6f 6e 3a 20 68 74 Location: ht
0980: 74 70 73 3a 2f 2f 61 70 70 2e 65 78 61 6d 70 6c tps://app.exampl
0990: 65 2e 63 6f 6d 2f 6c 6f 67 69 6e 2f 63 61 6c 6c e.com/login/call
09a0: 62 61 63 6b 3f 63 6f 64 65 3d 2e 2e 2e 26 73 74 back?code=...&st
09b0: 61 74 65 3d 31 32 33 34 35 36 37 38 39 30 0a 23 ate=1234567890.#
09c0: 0a 23 20 56 65 72 69 66 69 63 61 74 69 6f 6e 20 .# Verification
09d0: 72 65 71 75 65 73 74 3a 0a 23 20 20 20 20 3f 63 request:.# ?c
09e0: 6f 64 65 3d 24 31 79 24 2e 2e 2e 2e 2e 0a 23 20 ode=$1y$......#
09f0: 20 20 20 26 63 6c 69 65 6e 74 5f 69 64 3d 68 74 &client_id=ht
0a00: 74 70 3a 2f 2f 61 70 70 2e 65 78 61 6d 70 6c 65 tp://app.example
0a10: 2e 63 6f 6d 2f 0a 23 20 20 20 20 26 72 65 64 69 .com/.# &redi
0a20: 72 65 63 74 5f 75 72 69 3d 68 74 74 70 3a 2f 2f rect_uri=http://
0a30: 61 70 70 2e 65 78 61 6d 70 6c 65 2e 63 6f 6d 2f app.example.com/
0a40: 6c 6f 67 69 6e 2f 63 61 6c 6c 62 61 63 6b 0a 23 login/callback.#
0a50: 20 52 65 73 70 6f 6e 73 65 3a 0a 23 20 20 20 20 Response:.#
0a60: 7b 20 22 6d 65 22 3a 20 22 68 74 74 70 73 3a 2f { "me": "https:/
0a70: 2f 75 73 65 72 2e 65 78 61 6d 70 6c 65 2e 6f 72 /user.example.or
0a80: 67 2f 22 20 7d 0a 23 0a 23 0a 0a 69 66 20 28 24 g/" }.#.#..if ($
0a90: 5f 52 45 51 55 45 53 54 5b 22 64 62 67 22 5d 29 _REQUEST["dbg"])
0aa0: 20 7b 0a 20 20 20 20 65 72 72 6f 72 5f 72 65 70 {. error_rep
0ab0: 6f 72 74 69 6e 67 28 45 5f 41 4c 4c 29 3b 20 69 orting(E_ALL); i
0ac0: 6e 69 5f 73 65 74 28 22 64 69 73 70 6c 61 79 5f ni_set("display_
0ad0: 65 72 72 6f 72 73 22 2c 20 31 29 3b 0a 7d 0a 0a errors", 1);.}..
0ae0: 23 2d 2d 20 64 61 74 61 62 61 73 65 20 28 3d 3d #-- database (==
0af0: 20 66 6f 73 73 69 6c 20 72 65 70 6f 29 0a 66 75 fossil repo).fu
0b00: 6e 63 74 69 6f 6e 20 64 62 28 24 73 71 6c 3d 22 nction db($sql="
0b10: 22 2c 20 24 70 61 72 61 6d 73 3d 5b 5d 29 20 7b ", $params=[]) {
0b20: 0a 20 20 20 20 73 74 61 74 69 63 20 24 64 62 3b . static $db;
0b30: 0a 20 20 20 20 69 66 20 28 65 6d 70 74 79 28 24 . if (empty($
0b40: 64 62 29 29 20 7b 0a 20 20 20 20 20 20 20 20 24 db)) {. $
0b50: 64 62 20 3d 20 6e 65 77 20 50 44 4f 28 22 73 71 db = new PDO("sq
0b60: 6c 69 74 65 3a 24 5f 53 45 52 56 45 52 5b 46 4f lite:$_SERVER[FO
0b70: 53 53 49 4c 5f 52 45 50 4f 53 49 54 4f 52 59 5d SSIL_REPOSITORY]
0b80: 22 29 3b 0a 20 20 20 20 20 20 20 20 23 24 64 62 ");. #$db
0b90: 2d 3e 73 65 74 41 74 74 72 69 62 75 74 65 28 50 ->setAttribute(P
0ba0: 44 4f 3a 3a 41 54 54 52 5f 45 52 52 4d 4f 44 45 DO::ATTR_ERRMODE
0bb0: 2c 20 50 44 4f 3a 3a 45 52 52 4d 4f 44 45 5f 57 , PDO::ERRMODE_W
0bc0: 41 52 4e 49 4e 47 29 3b 0a 20 20 20 20 7d 0a 20 ARNING);. }.
0bd0: 20 20 20 69 66 20 28 24 70 61 72 61 6d 73 29 20 if ($params)
0be0: 7b 0a 20 20 20 20 20 20 20 20 24 73 74 6d 74 20 {. $stmt
0bf0: 3d 20 24 64 62 2d 3e 70 72 65 70 61 72 65 28 24 = $db->prepare($
0c00: 73 71 6c 29 3b 0a 20 20 20 20 20 20 20 20 24 73 sql);. $s
0c10: 74 6d 74 2d 3e 65 78 65 63 75 74 65 28 24 70 61 tmt->execute($pa
0c20: 72 61 6d 73 29 3b 0a 20 20 20 20 20 20 20 20 72 rams);. r
0c30: 65 74 75 72 6e 20 24 73 74 6d 74 2d 3e 66 65 74 eturn $stmt->fet
0c40: 63 68 41 6c 6c 28 29 3b 0a 20 20 20 20 7d 0a 20 chAll();. }.
0c50: 20 20 20 65 6c 73 65 20 7b 0a 20 20 20 20 20 20 else {.
0c60: 20 20 72 65 74 75 72 6e 20 24 64 62 2d 3e 71 75 return $db->qu
0c70: 65 72 79 28 24 73 71 6c 29 3b 0a 20 20 20 20 7d ery($sql);. }
0c80: 0a 7d 0a 66 75 6e 63 74 69 6f 6e 20 63 72 65 61 .}.function crea
0c90: 74 65 5f 74 61 62 6c 65 28 29 20 7b 0a 20 20 20 te_table() {.
0ca0: 20 64 62 28 22 43 52 45 41 54 45 20 54 41 42 4c db("CREATE TABL
0cb0: 45 20 49 46 20 4e 4f 54 20 45 58 49 53 54 53 20 E IF NOT EXISTS
0cc0: 60 66 78 5f 61 75 74 68 60 20 28 20 20 2d 2d 20 `fx_auth` ( --
0cd0: 49 6e 64 69 65 41 75 74 68 20 74 6f 6b 65 6e 20 IndieAuth token
0ce0: 74 61 62 6c 65 0a 20 20 20 20 20 20 20 20 60 63 table. `c
0cf0: 6f 64 65 60 20 54 45 58 54 2c 20 20 20 20 20 20 ode` TEXT,
0d00: 20 20 20 20 20 20 2d 2d 20 4f 41 75 74 68 20 61 -- OAuth a
0d10: 75 74 68 6f 72 69 7a 61 74 69 6f 6e 20 63 6f 64 uthorization cod
0d20: 65 0a 20 20 20 20 20 20 20 20 60 74 79 70 65 60 e. `type`
0d30: 20 54 45 58 54 2c 20 20 20 20 20 20 20 20 20 20 TEXT,
0d40: 20 20 2d 2d 20 6f 6e 65 20 6f 66 20 69 64 2c 63 -- one of id,c
0d50: 6f 64 65 2c 74 6f 6b 65 6e 2c 72 65 76 6f 6b 65 ode,token,revoke
0d60: 64 0a 20 20 20 20 20 20 20 20 60 73 63 6f 70 65 d. `scope
0d70: 60 20 54 45 58 54 2c 20 20 20 20 20 20 20 20 20 ` TEXT,
0d80: 20 20 2d 2d 20 70 65 72 6d 69 73 73 69 6f 6e 73 -- permissions
0d90: 20 28 63 72 65 61 74 65 2c 75 70 64 61 74 65 2c (create,update,
0da0: 64 65 6c 65 74 65 29 0a 20 20 20 20 20 20 20 20 delete).
0db0: 60 6c 6f 67 69 6e 60 20 54 45 58 54 2c 20 20 20 `login` TEXT,
0dc0: 20 20 20 20 20 20 20 20 2d 2d 20 66 6f 73 73 69 -- fossi
0dd0: 6c 20 75 73 65 72 20 61 63 63 6f 75 6e 74 0a 20 l user account.
0de0: 20 20 20 20 20 20 20 60 6d 65 60 20 54 45 58 54 `me` TEXT
0df0: 2c 20 20 20 20 20 20 20 20 20 20 20 20 20 20 2d , -
0e00: 2d 20 68 74 74 70 73 3a 2f 2f 75 73 65 72 77 65 - https://userwe
0e10: 62 69 64 2e 65 78 61 6d 70 6c 65 2e 6f 72 67 2f bid.example.org/
0e20: 0a 20 20 20 20 20 20 20 20 60 63 6c 69 65 6e 74 . `client
0e30: 5f 69 64 60 20 54 45 58 54 2c 20 20 20 20 20 20 _id` TEXT,
0e40: 20 2d 2d 20 68 74 74 70 73 3a 2f 2f 72 65 6d 6f -- https://remo
0e50: 74 65 61 70 70 2e 65 78 61 6d 70 6c 65 2e 63 6f teapp.example.co
0e60: 6d 2f 0a 20 20 20 20 20 20 20 20 60 72 65 64 69 m/. `redi
0e70: 72 65 63 74 5f 75 72 69 60 20 54 45 58 54 2c 20 rect_uri` TEXT,
0e80: 20 20 20 2d 2d 20 68 74 74 70 73 3a 2f 2f 61 70 -- https://ap
0e90: 70 2f 6c 6f 67 69 6e 2f 63 61 6c 6c 62 61 63 6b p/login/callback
0ea0: 0a 20 20 20 20 20 20 20 20 60 73 74 61 74 65 60 . `state`
0eb0: 20 54 45 58 54 2c 20 20 20 20 20 20 20 20 20 20 TEXT,
0ec0: 20 2d 2d 20 72 65 6d 6f 74 65 20 73 65 73 73 69 -- remote sessi
0ed0: 6f 6e 20 69 64 20 28 31 32 33 34 35 2e 2e 29 0a on id (12345..).
0ee0: 20 20 20 20 20 20 20 20 60 63 6f 64 65 5f 63 68 `code_ch
0ef0: 61 6c 6c 65 6e 67 65 60 20 54 45 58 54 2c 20 20 allenge` TEXT,
0f00: 2d 2d 20 70 72 65 2d 68 61 73 68 65 64 20 73 65 -- pre-hashed se
0f10: 63 72 65 74 20 66 6f 72 20 6c 61 74 65 72 20 74 cret for later t
0f20: 6f 6b 65 6e 20 72 65 71 0a 20 20 20 20 20 20 20 oken req.
0f30: 20 60 63 6f 64 65 5f 63 68 61 6c 6c 65 6e 67 65 `code_challenge
0f40: 5f 6d 60 20 54 45 58 54 2c 2d 2d 20 68 61 73 68 _m` TEXT,-- hash
0f50: 20 6d 65 74 68 6f 64 20 66 6f 72 20 73 65 63 72 method for secr
0f60: 65 74 0a 20 20 20 20 20 20 20 20 60 65 78 70 69 et. `expi
0f70: 72 65 73 60 20 49 4e 54 20 20 20 20 20 20 20 20 res` INT
0f80: 20 20 20 2d 2d 20 63 6f 64 65 20 76 61 6c 69 64 -- code valid
0f90: 20 75 6e 74 69 6c 20 74 69 6d 65 73 74 61 6d 70 until timestamp
0fa0: 0a 20 20 20 20 29 22 29 3b 0a 7d 0a 0a 23 2d 2d . )");.}..#--
0fb0: 20 66 6f 73 73 69 6c 20 48 54 4d 4c 20 6f 75 74 fossil HTML out
0fc0: 70 75 74 0a 66 75 6e 63 74 69 6f 6e 20 70 61 67 put.function pag
0fd0: 65 5f 68 74 6d 6c 28 24 68 74 6d 6c 29 20 7b 0a e_html($html) {.
0fe0: 20 20 20 20 68 65 61 64 65 72 28 22 43 6f 6e 74 header("Cont
0ff0: 65 6e 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 ent-Type: text/h
1000: 74 6d 6c 3b 20 65 6e 63 6f 64 69 6e 67 3d 75 74 tml; encoding=ut
1010: 66 2d 38 22 29 3b 0a 20 20 20 20 24 73 76 67 20 f-8");. $svg
1020: 3d 20 3c 3c 3c 53 56 47 0a 20 20 20 20 20 3c 73 = <<<SVG. <s
1030: 76 67 20 68 65 69 67 68 74 3d 32 37 30 20 77 69 vg height=270 wi
1040: 64 74 68 3d 32 31 35 20 73 74 79 6c 65 3d 27 66 dth=215 style='f
1050: 6c 6f 61 74 3a 6c 65 66 74 3b 20 6d 61 72 67 69 loat:left; margi
1060: 6e 2d 72 69 67 68 74 3a 20 33 30 70 74 3b 27 20 n-right: 30pt;'
1070: 76 69 65 77 42 6f 78 3d 27 30 20 30 20 34 32 2e viewBox='0 0 42.
1080: 39 36 37 38 36 31 20 35 33 2e 37 37 38 35 38 27 967861 53.77858'
1090: 3e 20 3c 67 20 74 72 61 6e 73 66 6f 72 6d 3d 27 > <g transform='
10a0: 74 72 61 6e 73 6c 61 74 65 28 2d 32 36 2e 39 32 translate(-26.92
10b0: 36 37 30 37 2c 2d 37 32 2e 32 34 34 30 34 38 29 6707,-72.244048)
10c0: 27 20 69 64 3d 27 6c 61 79 65 72 31 27 3e 0a 20 ' id='layer1'>.
10d0: 20 20 20 20 20 20 3c 70 61 74 68 20 69 64 3d 27 <path id='
10e0: 70 61 74 68 38 32 38 27 20 64 3d 27 6d 20 35 38 path828' d='m 58
10f0: 2e 36 36 37 30 33 32 2c 37 33 2e 31 32 36 35 32 .667032,73.12652
1100: 36 20 63 20 2d 36 2e 33 35 39 34 37 2c 30 2e 30 6 c -6.35947,0.0
1110: 34 34 34 34 20 2d 31 32 2e 37 31 38 39 35 2c 30 4444 -12.71895,0
1120: 2e 30 38 38 38 38 20 2d 31 39 2e 30 37 38 34 31 .08888 -19.07841
1130: 38 2c 30 2e 31 33 33 33 32 37 20 2d 33 2e 38 35 8,0.133327 -3.85
1140: 33 36 38 33 2c 31 37 2e 32 39 33 33 35 20 2d 37 3683,17.29335 -7
1150: 2e 37 30 37 33 36 37 2c 33 34 2e 35 38 36 36 38 .707367,34.58668
1160: 37 20 2d 31 31 2e 35 36 31 30 35 2c 35 31 2e 38 7 -11.56105,51.8
1170: 38 30 30 33 37 20 34 2e 36 37 30 38 36 2c 2d 31 80037 4.67086,-1
1180: 30 65 2d 34 20 39 2e 33 34 31 37 31 39 2c 2d 30 0e-4 9.341719,-0
1190: 2e 30 30 32 20 31 34 2e 30 31 32 35 37 38 2c 2d .002 14.012578,-
11a0: 30 2e 30 30 33 20 30 2e 31 37 38 31 31 2c 2d 36 0.003 0.17811,-6
11b0: 2e 33 32 36 32 33 20 30 2e 33 35 36 32 33 2c 2d .32623 0.35623,-
11c0: 31 32 2e 36 35 32 34 36 20 30 2e 35 33 34 33 34 12.65246 0.53434
11d0: 2c 2d 31 38 2e 39 37 38 36 39 20 32 2e 30 34 35 ,-18.97869 2.045
11e0: 35 32 2c 2d 30 2e 38 35 38 38 36 20 34 2e 30 39 52,-0.85886 4.09
11f0: 31 30 34 2c 2d 31 2e 37 31 37 37 33 20 36 2e 31 104,-1.71773 6.1
1200: 33 36 35 37 2c 2d 32 2e 35 37 36 35 39 20 32 2e 3657,-2.57659 2.
1210: 31 33 38 38 39 2c 30 2e 38 39 35 39 20 34 2e 32 13889,0.8959 4.2
1220: 37 37 37 37 2c 31 2e 37 39 31 37 39 20 36 2e 34 7777,1.79179 6.4
1230: 31 36 36 36 2c 32 2e 36 38 37 36 39 20 2d 30 2e 1666,2.68769 -0.
1240: 31 30 35 39 34 2c 35 2e 39 36 31 36 31 20 30 2e 10594,5.96161 0.
1250: 36 34 30 35 39 2c 31 31 2e 39 33 32 34 31 20 30 64059,11.93241 0
1260: 2e 31 37 38 32 35 2c 31 37 2e 38 38 33 36 38 20 .17825,17.88368
1270: 2d 30 2e 38 32 31 34 33 2c 31 2e 32 37 39 31 35 -0.82143,1.27915
1280: 20 31 2e 32 39 38 38 39 2c 30 2e 35 30 37 34 38 1.29889,0.50748
1290: 20 32 2e 30 35 35 33 33 2c 30 2e 37 31 38 32 37 2.05533,0.71827
12a0: 20 33 2e 38 32 30 32 33 2c 30 2e 30 30 32 20 37 3.82023,0.002 7
12b0: 2e 36 34 30 34 35 2c 30 2e 30 30 35 20 31 31 2e .64045,0.005 11.
12c0: 34 36 30 36 37 2c 30 2e 30 30 37 20 2d 33 2e 33 46067,0.007 -3.3
12d0: 38 34 39 38 2c 2d 31 37 2e 32 35 30 37 33 20 2d 8498,-17.25073 -
12e0: 36 2e 37 36 39 39 35 2c 2d 33 34 2e 35 30 31 34 6.76995,-34.5014
12f0: 35 37 20 2d 31 30 2e 31 35 34 39 33 2c 2d 35 31 57 -10.15493,-51
1300: 2e 37 35 32 31 39 34 20 7a 20 6d 20 2d 39 2e 34 .752194 z m -9.4
1310: 38 39 33 34 2c 37 2e 35 31 38 39 32 32 20 63 20 8934,7.518922 c
1320: 34 2e 37 36 36 33 39 2c 2d 30 2e 31 38 30 39 38 4.76639,-0.18098
1330: 38 20 38 2e 35 39 37 33 32 2c 35 2e 30 32 36 33 8 8.59732,5.0263
1340: 33 39 20 37 2e 30 32 31 36 36 2c 39 2e 35 32 31 39 7.02166,9.521
1350: 39 38 35 20 2d 31 2e 32 33 36 35 35 2c 34 2e 36 985 -1.23655,4.6
1360: 30 33 39 35 20 2d 37 2e 33 34 31 30 39 2c 36 2e 0395 -7.34109,6.
1370: 37 33 33 31 20 2d 31 31 2e 31 37 31 37 34 2c 33 7331 -11.17174,3
1380: 2e 38 39 34 31 34 20 2d 34 2e 30 33 34 34 37 34 .89414 -4.034474
1390: 2c 2d 32 2e 35 34 31 39 36 20 2d 34 2e 32 36 33 ,-2.54196 -4.263
13a0: 32 38 34 2c 2d 39 2e 30 30 32 35 37 34 20 2d 30 284,-9.002574 -0
13b0: 2e 34 31 38 37 35 2c 2d 31 31 2e 38 32 33 35 38 .41875,-11.82358
13c0: 20 31 2e 32 38 35 39 35 2c 2d 31 2e 30 32 35 38 1.28595,-1.0258
13d0: 36 38 20 32 2e 39 32 34 30 35 2c 2d 31 2e 35 39 68 2.92405,-1.59
13e0: 36 36 34 35 20 34 2e 35 36 38 38 33 2c 2d 31 2e 6645 4.56883,-1.
13f0: 35 39 32 35 34 35 20 7a 20 6d 20 35 2e 36 38 32 592545 z m 5.682
1400: 38 35 2c 34 34 2e 32 32 34 31 37 32 20 63 20 30 85,44.224172 c 0
1410: 2e 33 32 37 32 34 2c 30 20 30 2e 30 39 38 36 2c .32724,0 0.0986,
1420: 30 20 30 2c 30 20 7a 27 0a 20 20 20 20 20 20 20 0 0,0 z'.
1430: 73 74 79 6c 65 3d 27 66 69 6c 6c 3a 23 61 65 65 style='fill:#aee
1440: 61 34 37 3b 66 69 6c 6c 2d 6f 70 61 63 69 74 79 a47;fill-opacity
1450: 3a 31 3b 73 74 72 6f 6b 65 3a 23 34 61 35 38 34 :1;stroke:#4a584
1460: 38 3b 73 74 72 6f 6b 65 2d 77 69 64 74 68 3a 31 8;stroke-width:1
1470: 2e 37 36 34 39 39 39 39 39 3b 73 74 72 6f 6b 65 .76499999;stroke
1480: 2d 6c 69 6e 65 63 61 70 3a 62 75 74 74 3b 73 74 -linecap:butt;st
1490: 72 6f 6b 65 2d 6c 69 6e 65 6a 6f 69 6e 3a 6d 69 roke-linejoin:mi
14a0: 74 65 72 3b 73 74 72 6f 6b 65 2d 6d 69 74 65 72 ter;stroke-miter
14b0: 6c 69 6d 69 74 3a 34 3b 73 74 72 6f 6b 65 2d 64 limit:4;stroke-d
14c0: 61 73 68 61 72 72 61 79 3a 6e 6f 6e 65 3b 73 74 asharray:none;st
14d0: 72 6f 6b 65 2d 6f 70 61 63 69 74 79 3a 30 2e 39 roke-opacity:0.9
14e0: 39 34 35 36 35 31 38 27 20 2f 3e 0a 20 20 20 20 9456518' />.
14f0: 20 3c 2f 67 3e 3c 2f 73 76 67 3e 0a 53 56 47 3b </g></svg>.SVG;
1500: 0a 20 20 20 20 70 72 69 6e 74 28 22 3c 64 69 76 . print("<div
1510: 20 63 6c 61 73 73 3d 27 66 6f 73 73 69 6c 2d 64 class='fossil-d
1520: 6f 63 27 20 64 61 74 61 2d 74 69 74 6c 65 3d 27 oc' data-title='
1530: 49 6e 64 69 65 41 75 74 68 27 3e 5c 6e 24 73 76 IndieAuth'>\n$sv
1540: 67 5c 6e 24 68 74 6d 6c 5c 6e 3c 2f 64 69 76 3e g\n$html\n</div>
1550: 22 29 3b 0a 7d 0a 66 75 6e 63 74 69 6f 6e 20 6d ");.}.function m
1560: 69 73 73 69 6e 67 5f 70 61 72 61 6d 28 24 6e 61 issing_param($na
1570: 6d 65 29 20 7b 0a 20 20 20 20 64 69 65 28 70 61 me) {. die(pa
1580: 67 65 5f 68 74 6d 6c 28 22 3c 68 32 3e 4d 69 73 ge_html("<h2>Mis
1590: 73 69 6e 67 20 69 6e 70 75 74 3c 2f 68 32 3e 3c sing input</h2><
15a0: 70 3e 55 52 4c 20 6c 61 63 6b 73 20 3c 63 6f 64 p>URL lacks <cod
15b0: 65 3e 26 24 6e 61 6d 65 3d 3c 2f 63 6f 64 65 3e e>&$name=</code>
15c0: 20 70 61 72 61 6d 65 74 65 72 2e 3c 70 3e 43 61 parameter.<p>Ca
15d0: 6e 27 74 20 70 72 6f 63 65 73 73 20 61 73 20 49 n't process as I
15e0: 6e 64 69 65 41 75 74 68 2f 4f 41 75 74 68 20 72 ndieAuth/OAuth r
15f0: 65 71 75 65 73 74 2e 22 29 29 3b 0a 7d 0a 66 75 equest."));.}.fu
1600: 6e 63 74 69 6f 6e 20 70 61 67 65 5f 6d 64 28 24 nction page_md($
1610: 74 65 78 74 29 20 7b 0a 20 20 20 20 68 65 61 64 text) {. head
1620: 65 72 28 22 43 6f 6e 74 65 6e 74 2d 54 79 70 65 er("Content-Type
1630: 3a 20 74 65 78 74 2f 78 2d 6d 61 72 6b 64 6f 77 : text/x-markdow
1640: 6e 3b 20 65 6e 63 6f 64 69 6e 67 3d 75 74 66 2d n; encoding=utf-
1650: 38 22 29 3b 0a 20 20 20 20 70 72 69 6e 74 28 24 8");. print($
1660: 74 65 78 74 29 3b 0a 7d 0a 66 75 6e 63 74 69 6f text);.}.functio
1670: 6e 20 68 28 24 73 29 20 7b 0a 20 20 20 20 72 65 n h($s) {. re
1680: 74 75 72 6e 20 68 74 6d 6c 73 70 65 63 69 61 6c turn htmlspecial
1690: 63 68 61 72 73 28 24 73 2c 20 45 4e 54 5f 51 55 chars($s, ENT_QU
16a0: 4f 54 45 53 7c 45 4e 54 5f 48 54 4d 4c 35 2c 20 OTES|ENT_HTML5,
16b0: 22 55 54 46 2d 38 22 29 3b 0a 7d 0a 0a 0a 23 2d "UTF-8");.}...#-
16c0: 2d 20 74 65 73 74 20 69 66 20 68 74 74 70 3a 2f - test if http:/
16d0: 2f 69 64 65 6e 74 69 74 79 2f 20 69 73 20 77 68 /identity/ is wh
16e0: 69 74 65 6c 69 73 74 65 64 20 69 6e 20 75 73 65 itelisted in use
16f0: 72 2e 60 68 6f 6d 65 70 61 67 65 60 2f 60 69 6e r.`homepage`/`in
1700: 66 6f 60 20 63 6f 6c 75 6d 6e 0a 66 75 6e 63 74 fo` column.funct
1710: 69 6f 6e 20 61 6c 6c 6f 77 65 64 5f 69 64 65 6e ion allowed_iden
1720: 74 69 74 79 28 24 75 73 65 72 2c 20 24 75 72 6c tity($user, $url
1730: 29 20 7b 0a 20 20 20 20 24 61 6c 6c 20 3d 20 64 ) {. $all = d
1740: 62 28 22 53 45 4c 45 43 54 20 2a 20 46 52 4f 4d b("SELECT * FROM
1750: 20 75 73 65 72 20 57 48 45 52 45 20 6c 6f 67 69 user WHERE logi
1760: 6e 3d 3f 22 2c 20 5b 24 75 73 65 72 5d 29 3b 0a n=?", [$user]);.
1770: 20 20 20 20 70 72 65 67 5f 6d 61 74 63 68 5f 61 preg_match_a
1780: 6c 6c 28 22 7e 5c 5c 62 20 68 74 74 70 73 3f 3a ll("~\\b https?:
1790: 2f 2f 28 5c 53 2b 29 20 28 3f 3c 21 5b 2c 3b 7c //(\S+) (?<![,;|
17a0: 3c 3e 27 5c 22 5d 29 7e 78 22 2c 20 6a 6f 69 6e <>'\"])~x", join
17b0: 28 22 2c 20 22 2c 20 24 61 6c 6c 5b 30 5d 29 2c (", ", $all[0]),
17c0: 20 24 75 75 29 3b 20 20 23 20 73 65 61 72 63 68 $uu); # search
17d0: 20 61 6c 6c 20 66 69 65 6c 64 73 20 66 6f 72 20 all fields for
17e0: 75 72 6c 73 0a 20 20 20 20 66 6f 72 65 61 63 68 urls. foreach
17f0: 20 28 24 75 75 5b 31 5d 20 61 73 20 24 69 74 65 ($uu[1] as $ite
1800: 6d 29 20 7b 0a 20 20 20 20 20 20 20 20 69 66 20 m) {. if
1810: 28 74 72 69 6d 5f 75 72 6c 28 24 69 74 65 6d 29 (trim_url($item)
1820: 20 3d 3d 20 74 72 69 6d 5f 75 72 6c 28 24 75 72 == trim_url($ur
1830: 6c 29 29 20 7b 0a 20 20 20 20 20 20 20 20 20 20 l)) {.
1840: 20 20 20 72 65 74 75 72 6e 20 54 72 75 65 3b 0a return True;.
1850: 20 20 20 20 20 20 20 20 7d 0a 20 20 20 20 7d 0a }. }.
1860: 7d 0a 66 75 6e 63 74 69 6f 6e 20 74 72 69 6d 5f }.function trim_
1870: 75 72 6c 28 24 75 72 6c 29 20 7b 0a 20 20 20 20 url($url) {.
1880: 23 20 56 65 72 79 20 63 72 75 64 65 20 55 52 4c # Very crude URL
1890: 20 65 71 75 61 6c 69 74 79 20 74 65 73 74 2e 0a equality test..
18a0: 20 20 20 20 23 20 53 74 72 69 70 20 61 6e 79 20 # Strip any
18b0: 68 74 74 70 3a 2f 2f 20 70 72 65 66 69 78 2c 20 http:// prefix,
18c0: 74 72 61 69 6c 69 6e 67 20 73 6c 61 73 68 65 73 trailing slashes
18d0: 2c 20 6f 72 20 2f 68 6f 6d 65 2c 20 2f 69 6e 64 , or /home, /ind
18e0: 65 78 20 28 77 68 65 6e 20 72 65 66 65 72 72 69 ex (when referri
18f0: 6e 67 20 74 6f 20 66 6f 73 73 69 6c 20 69 6e 73 ng to fossil ins
1900: 74 61 6e 63 65 29 2e 0a 20 20 20 20 72 65 74 75 tance).. retu
1910: 72 6e 20 73 74 72 74 6f 6c 6f 77 65 72 28 70 72 rn strtolower(pr
1920: 65 67 5f 72 65 70 6c 61 63 65 28 22 7e 20 5e 68 eg_replace("~ ^h
1930: 74 74 70 73 3f 3a 2f 2f 20 7c 20 2f 2b 28 68 6f ttps?:// | /+(ho
1940: 6d 65 7c 69 6e 64 65 78 29 24 20 7c 20 2f 2b 24 me|index)$ | /+$
1950: 20 7e 78 22 2c 20 22 22 2c 20 24 75 72 6c 29 29 ~x", "", $url))
1960: 3b 0a 7d 0a 66 75 6e 63 74 69 6f 6e 20 62 61 73 ;.}.function bas
1970: 65 36 34 5f 75 72 6c 65 6e 63 6f 64 65 28 24 72 e64_urlencode($r
1980: 61 77 29 20 7b 0a 20 20 20 20 72 65 74 75 72 6e aw) {. return
1990: 20 73 74 72 74 72 28 74 72 69 6d 28 62 61 73 65 strtr(trim(base
19a0: 36 34 5f 65 6e 63 6f 64 65 28 24 72 61 77 29 2c 64_encode($raw),
19b0: 20 22 3d 22 29 2c 20 22 2b 2f 22 2c 20 22 2d 5f "="), "+/", "-_
19c0: 22 29 3b 0a 7d 0a 0a 23 2d 2d 20 6c 6f 61 64 20 ");.}..#-- load
19d0: 61 75 74 68 6f 72 69 7a 61 74 69 6f 6e 20 70 72 authorization pr
19e0: 6f 70 65 72 74 69 65 73 20 62 79 20 61 75 74 68 operties by auth
19f0: 20 63 6f 64 65 0a 66 75 6e 63 74 69 6f 6e 20 67 code.function g
1a00: 65 74 5f 74 6f 6b 65 6e 5f 62 79 5f 63 6f 64 65 et_token_by_code
1a10: 28 24 63 6f 64 65 29 20 7b 0a 20 20 20 20 72 65 ($code) {. re
1a20: 74 75 72 6e 20 64 62 28 22 53 45 4c 45 43 54 20 turn db("SELECT
1a30: 2a 20 46 52 4f 4d 20 66 78 5f 61 75 74 68 20 57 * FROM fx_auth W
1a40: 48 45 52 45 20 63 6f 64 65 3d 3f 22 2c 20 5b 24 HERE code=?", [$
1a50: 63 6f 64 65 5d 29 20 3f 3a 20 5b 5b 5d 5d 3b 0a code]) ?: [[]];.
1a60: 7d 0a 66 75 6e 63 74 69 6f 6e 20 63 6c 65 61 6e }.function clean
1a70: 5f 65 78 70 69 72 65 64 5f 74 6f 6b 65 6e 28 29 _expired_token()
1a80: 20 7b 0a 20 20 20 20 64 62 28 22 44 45 4c 45 54 {. db("DELET
1a90: 45 20 46 52 4f 4d 20 66 78 5f 61 75 74 68 20 57 E FROM fx_auth W
1aa0: 48 45 52 45 20 65 78 70 69 72 65 73 20 3c 20 3f HERE expires < ?
1ab0: 22 2c 20 5b 74 69 6d 65 28 29 5d 29 3b 0a 7d 0a ", [time()]);.}.
1ac0: 0a 0a 23 2d 2d 20 3c 66 6f 72 6d 3e 20 63 68 65 ..#-- <form> che
1ad0: 63 6b 62 6f 78 65 73 20 66 6f 72 20 22 73 63 6f ckboxes for "sco
1ae0: 70 65 22 20 74 6f 6b 65 6e 20 72 65 71 75 65 73 pe" token reques
1af0: 74 2c 20 65 78 74 65 6e 64 65 64 20 64 65 66 61 t, extended defa
1b00: 75 6c 74 20 6c 69 73 74 20 61 6e 64 20 3f 73 63 ult list and ?sc
1b10: 6f 70 65 3d e2 80 a6 20 72 65 71 75 65 73 74 73 ope=โฆ requests
1b20: 0a 66 75 6e 63 74 69 6f 6e 20 73 63 6f 70 65 5f .function scope_
1b30: 6c 69 73 74 28 24 68 74 6d 6c 3d 22 22 29 20 7b list($html="") {
1b40: 0a 20 20 20 20 24 73 63 6f 70 65 73 20 3d 20 5b . $scopes = [
1b50: 22 63 72 65 61 74 65 22 3d 3e 22 63 68 65 63 6b "create"=>"check
1b60: 65 64 22 2c 20 22 75 70 64 61 74 65 22 3d 3e 22 ed", "update"=>"
1b70: 63 68 65 63 6b 65 64 22 2c 20 22 64 65 6c 65 74 checked", "delet
1b80: 65 22 3d 3e 22 22 2c 20 22 74 69 63 6b 65 74 22 e"=>"", "ticket"
1b90: 3d 3e 22 63 68 65 63 6b 65 64 22 2c 20 22 77 69 =>"checked", "wi
1ba0: 6b 69 22 3d 3e 22 22 2c 20 22 66 6f 72 75 6d 22 ki"=>"", "forum"
1bb0: 3d 3e 22 22 5d 3b 0a 20 20 20 20 69 66 20 28 21 =>""];. if (!
1bc0: 65 6d 70 74 79 28 24 5f 52 45 51 55 45 53 54 5b empty($_REQUEST[
1bd0: 22 73 63 6f 70 65 22 5d 29 20 61 6e 64 20 70 72 "scope"]) and pr
1be0: 65 67 5f 6d 61 74 63 68 5f 61 6c 6c 28 22 2f 28 eg_match_all("/(
1bf0: 5c 77 2b 29 2f 22 2c 20 24 5f 52 45 51 55 45 53 \w+)/", $_REQUES
1c00: 54 5b 22 73 63 6f 70 65 22 5d 2c 20 24 75 75 29 T["scope"], $uu)
1c10: 29 20 7b 0a 20 20 20 20 20 20 20 20 66 6f 72 65 ) {. fore
1c20: 61 63 68 20 28 24 75 75 5b 31 5d 20 61 73 20 24 ach ($uu[1] as $
1c30: 66 69 65 6c 64 29 20 7b 20 24 73 63 6f 70 65 73 field) { $scopes
1c40: 5b 24 66 69 65 6c 64 5d 20 3d 20 22 63 68 65 63 [$field] = "chec
1c50: 6b 65 64 22 3b 20 7d 0a 20 20 20 20 7d 0a 20 20 ked"; }. }.
1c60: 20 20 66 6f 72 65 61 63 68 20 28 24 73 63 6f 70 foreach ($scop
1c70: 65 73 20 61 73 20 24 66 69 65 6c 64 3d 3e 24 63 es as $field=>$c
1c80: 68 65 63 6b 65 64 29 20 7b 0a 20 20 20 20 20 20 hecked) {.
1c90: 20 20 24 68 74 6d 6c 20 2e 3d 20 22 3c 6c 69 20 $html .= "<li
1ca0: 73 74 79 6c 65 3d 27 66 6c 65 78 3a 20 31 20 30 style='flex: 1 0
1cb0: 20 33 33 25 3b 20 6c 69 73 74 2d 73 74 79 6c 65 33%; list-style
1cc0: 2d 74 79 70 65 3a 20 6e 6f 6e 65 3b 27 3e 20 3c -type: none;'> <
1cd0: 6c 61 62 65 6c 3e 3c 69 6e 70 75 74 20 74 79 70 label><input typ
1ce0: 65 3d 63 68 65 63 6b 62 6f 78 20 24 63 68 65 63 e=checkbox $chec
1cf0: 6b 65 64 20 6e 61 6d 65 3d 27 73 63 6f 70 65 5b ked name='scope[
1d00: 5d 27 20 76 61 6c 75 65 3d 24 66 69 65 6c 64 3e ]' value=$field>
1d10: 20 24 66 69 65 6c 64 3c 2f 6c 61 62 65 6c 3e 5c $field</label>\
1d20: 6e 22 3b 0a 20 20 20 20 7d 0a 20 20 20 20 72 65 n";. }. re
1d30: 74 75 72 6e 20 24 68 74 6d 6c 3b 0a 7d 0a 0a 23 turn $html;.}..#
1d40: 2d 2d 20 69 6e 69 74 69 61 6c 20 61 75 74 68 6f -- initial autho
1d50: 72 69 7a 61 74 69 6f 6e 20 72 65 71 75 65 73 74 rization request
1d60: 0a 66 75 6e 63 74 69 6f 6e 20 70 72 6f 63 65 73 .function proces
1d70: 73 5f 72 65 71 75 65 73 74 28 29 20 7b 0a 0a 20 s_request() {..
1d80: 20 20 20 23 20 69 6e 70 75 74 20 70 61 72 61 6d # input param
1d90: 73 0a 20 20 20 20 24 75 73 65 72 20 3d 20 24 5f s. $user = $_
1da0: 53 45 52 56 45 52 5b 22 46 4f 53 53 49 4c 5f 55 SERVER["FOSSIL_U
1db0: 53 45 52 22 5d 3b 0a 20 20 20 20 24 73 65 63 72 SER"];. $secr
1dc0: 65 74 20 3d 20 24 5f 53 45 52 56 45 52 5b 22 46 et = $_SERVER["F
1dd0: 4f 53 53 49 4c 5f 4e 4f 4e 43 45 22 5d 3b 0a 20 OSSIL_NONCE"];.
1de0: 20 20 20 24 6d 65 20 3d 20 24 5f 52 45 51 55 45 $me = $_REQUE
1df0: 53 54 5b 22 6d 65 22 5d 20 6f 72 20 6d 69 73 73 ST["me"] or miss
1e00: 69 6e 67 5f 70 61 72 61 6d 28 22 6d 65 22 29 3b ing_param("me");
1e10: 0a 20 20 20 20 24 63 6c 69 65 6e 74 5f 69 64 20 . $client_id
1e20: 3d 20 24 5f 52 45 51 55 45 53 54 5b 22 63 6c 69 = $_REQUEST["cli
1e30: 65 6e 74 5f 69 64 22 5d 20 6f 72 20 6d 69 73 73 ent_id"] or miss
1e40: 69 6e 67 5f 70 61 72 61 6d 28 22 63 6c 69 65 6e ing_param("clien
1e50: 74 5f 69 64 22 29 3b 0a 20 20 20 20 24 72 65 64 t_id");. $red
1e60: 69 72 65 63 74 5f 75 72 69 20 3d 20 24 5f 52 45 irect_uri = $_RE
1e70: 51 55 45 53 54 5b 22 72 65 64 69 72 65 63 74 5f QUEST["redirect_
1e80: 75 72 69 22 5d 20 6f 72 20 6d 69 73 73 69 6e 67 uri"] or missing
1e90: 5f 70 61 72 61 6d 28 22 72 65 64 69 72 65 63 74 _param("redirect
1ea0: 5f 75 72 69 22 29 3b 0a 20 20 20 20 24 73 74 61 _uri");. $sta
1eb0: 74 65 20 3d 20 24 5f 52 45 51 55 45 53 54 5b 22 te = $_REQUEST["
1ec0: 73 74 61 74 65 22 5d 20 3f 3a 20 22 22 3b 0a 20 state"] ?: "";.
1ed0: 20 20 20 24 63 6f 64 65 5f 63 68 61 6c 6c 65 6e $code_challen
1ee0: 67 65 20 3d 20 24 5f 52 45 51 55 45 53 54 5b 22 ge = $_REQUEST["
1ef0: 63 6f 64 65 5f 63 68 61 6c 6c 65 6e 67 65 22 5d code_challenge"]
1f00: 20 3f 3a 20 22 22 3b 0a 20 20 20 20 24 63 6f 64 ?: "";. $cod
1f10: 65 5f 63 68 61 6c 6c 65 6e 67 65 5f 6d 20 3d 20 e_challenge_m =
1f20: 24 5f 52 45 51 55 45 53 54 5b 22 63 6f 64 65 5f $_REQUEST["code_
1f30: 63 68 61 6c 6c 65 6e 67 65 5f 6d 65 74 68 6f 64 challenge_method
1f40: 22 5d 20 3f 3a 20 22 53 32 35 36 22 3b 0a 20 20 "] ?: "S256";.
1f50: 20 20 24 72 65 73 70 6f 6e 73 65 5f 74 79 70 65 $response_type
1f60: 20 3d 20 24 5f 52 45 51 55 45 53 54 5b 22 72 65 = $_REQUEST["re
1f70: 73 70 6f 6e 73 65 5f 74 79 70 65 22 5d 20 3f 3a sponse_type"] ?:
1f80: 20 22 69 64 22 3b 0a 20 20 20 20 24 68 20 3d 20 "id";. $h =
1f90: 22 68 22 3b 0a 0a 20 20 20 20 23 20 63 68 65 63 "h";.. # chec
1fa0: 6b 20 69 66 20 24 6d 65 20 69 73 20 61 6c 6c 6f k if $me is allo
1fb0: 77 65 64 0a 20 20 20 20 69 66 20 28 21 61 6c 6c wed. if (!all
1fc0: 6f 77 65 64 5f 69 64 65 6e 74 69 74 79 28 24 75 owed_identity($u
1fd0: 73 65 72 2c 20 24 6d 65 29 29 20 7b 0a 20 20 20 ser, $me)) {.
1fe0: 20 20 20 20 20 72 65 74 75 72 6e 20 70 61 67 65 return page
1ff0: 5f 68 74 6d 6c 28 22 3c 68 32 3e 49 6e 76 61 6c _html("<h2>Inval
2000: 69 64 20 69 64 65 6e 74 69 74 79 3c 2f 68 32 3e id identity</h2>
2010: 20 55 73 65 72 20 64 6f 65 73 6e 27 74 20 68 61 User doesn't ha
2020: 76 65 20 27 7b 24 68 28 24 6d 65 29 7d 27 20 72 ve '{$h($me)}' r
2030: 65 73 65 72 76 65 64 20 69 6e 20 75 73 65 72 20 eserved in user
2040: 74 61 62 6c 65 2e 22 29 3b 0a 20 20 20 20 7d 0a table.");. }.
2050: 20 20 20 20 0a 20 20 20 20 23 20 6e 65 77 20 63 . # new c
2060: 6f 64 65 20 2f 2f 20 68 61 73 68 69 6e 67 20 74 ode // hashing t
2070: 68 65 20 70 72 6f 70 65 72 74 69 65 73 20 69 73 he properties is
2080: 20 61 20 62 69 74 20 6f 76 65 72 6b 69 6c 6c 2c a bit overkill,
2090: 20 61 6e 79 20 72 61 6e 64 6f 6d 20 69 64 20 77 any random id w
20a0: 6f 75 6c 64 20 73 75 66 66 69 63 65 0a 20 20 20 ould suffice.
20b0: 20 24 63 6f 64 65 20 3d 20 70 61 73 73 77 6f 72 $code = passwor
20c0: 64 5f 68 61 73 68 28 22 24 6d 65 2f 24 63 6c 69 d_hash("$me/$cli
20d0: 65 6e 74 5f 69 64 2f 24 73 74 61 74 65 2f 24 73 ent_id/$state/$s
20e0: 65 63 72 65 74 22 2c 20 50 41 53 53 57 4f 52 44 ecret", PASSWORD
20f0: 5f 44 45 46 41 55 4c 54 29 3b 0a 20 20 20 20 64 _DEFAULT);. d
2100: 62 28 22 0a 20 20 20 20 20 20 20 20 49 4e 53 45 b(". INSE
2110: 52 54 20 49 4e 54 4f 20 66 78 5f 61 75 74 68 0a RT INTO fx_auth.
2120: 20 20 20 20 20 20 20 20 28 60 63 6f 64 65 60 2c (`code`,
2130: 20 60 74 79 70 65 60 2c 20 60 6c 6f 67 69 6e 60 `type`, `login`
2140: 2c 20 60 6d 65 60 2c 20 60 63 6c 69 65 6e 74 5f , `me`, `client_
2150: 69 64 60 2c 20 60 72 65 64 69 72 65 63 74 5f 75 id`, `redirect_u
2160: 72 69 60 2c 20 60 73 74 61 74 65 60 2c 20 60 63 ri`, `state`, `c
2170: 6f 64 65 5f 63 68 61 6c 6c 65 6e 67 65 60 2c 20 ode_challenge`,
2180: 60 63 6f 64 65 5f 63 68 61 6c 6c 65 6e 67 65 5f `code_challenge_
2190: 6d 60 2c 20 60 65 78 70 69 72 65 73 60 29 0a 20 m`, `expires`).
21a0: 20 20 20 20 20 20 20 56 41 4c 55 45 53 20 28 3f VALUES (?
21b0: 2c 20 3f 2c 20 3f 2c 20 3f 2c 20 3f 2c 20 3f 2c , ?, ?, ?, ?, ?,
21c0: 20 3f 2c 20 3f 2c 20 3f 2c 20 3f 29 22 2c 0a 20 ?, ?, ?, ?)",.
21d0: 20 20 20 20 20 20 20 5b 24 63 6f 64 65 2c 20 24 [$code, $
21e0: 72 65 73 70 6f 6e 73 65 5f 74 79 70 65 2c 20 24 response_type, $
21f0: 75 73 65 72 2c 20 24 6d 65 2c 20 24 63 6c 69 65 user, $me, $clie
2200: 6e 74 5f 69 64 2c 20 24 72 65 64 69 72 65 63 74 nt_id, $redirect
2210: 5f 75 72 69 2c 20 24 73 74 61 74 65 2c 20 24 63 _uri, $state, $c
2220: 6f 64 65 5f 63 68 61 6c 6c 65 6e 67 65 2c 20 24 ode_challenge, $
2230: 63 6f 64 65 5f 63 68 61 6c 6c 65 6e 67 65 5f 6d code_challenge_m
2240: 2c 20 74 69 6d 65 28 29 2b 33 30 30 5d 0a 20 20 , time()+300].
2250: 20 20 29 3b 0a 0a 20 20 20 20 23 20 63 6f 6e 73 );.. # cons
2260: 74 72 75 63 74 20 63 6f 6e 66 69 72 6d 61 74 69 truct confirmati
2270: 6f 6e 2b 72 65 64 69 72 65 63 74 20 75 72 6c 0a on+redirect url.
2280: 20 20 20 20 24 75 72 6c 20 3d 20 24 72 65 64 69 $url = $redi
2290: 72 65 63 74 5f 75 72 69 0a 20 20 20 20 20 20 20 rect_uri.
22a0: 20 20 2e 20 28 73 74 72 73 74 72 28 24 72 65 64 . (strstr($red
22b0: 69 72 65 63 74 5f 75 72 69 2c 20 22 3f 22 29 20 irect_uri, "?")
22c0: 3f 20 22 26 22 20 3a 20 22 3f 22 29 0a 20 20 20 ? "&" : "?").
22d0: 20 20 20 20 20 20 2e 20 22 63 6f 64 65 3d 22 20 . "code="
22e0: 2e 20 75 72 6c 65 6e 63 6f 64 65 28 24 63 6f 64 . urlencode($cod
22f0: 65 29 20 2e 20 22 26 73 74 61 74 65 3d 22 20 2e e) . "&state=" .
2300: 20 75 72 6c 65 6e 63 6f 64 65 28 24 73 74 61 74 urlencode($stat
2310: 65 29 3b 0a 20 20 20 20 0a 20 20 20 20 23 20 6f e);. . # o
2320: 75 74 70 75 74 20 70 61 67 65 0a 20 20 20 20 69 utput page. i
2330: 66 20 28 24 72 65 73 70 6f 6e 73 65 5f 74 79 70 f ($response_typ
2340: 65 20 3d 3d 20 22 63 6f 64 65 22 29 20 7b 0a 20 e == "code") {.
2350: 20 20 20 20 20 20 20 24 73 63 6f 70 65 20 3d 20 $scope =
2360: 73 63 6f 70 65 5f 6c 69 73 74 28 29 3b 0a 20 20 scope_list();.
2370: 20 20 7d 0a 20 20 20 20 24 68 74 6d 6c 20 3d 20 }. $html =
2380: 3c 3c 3c 48 54 4d 4c 0a 0a 20 20 20 20 3c 68 32 <<<HTML.. <h2
2390: 3e 4c 6f 67 69 6e 20 72 65 71 75 65 73 74 3c 2f >Login request</
23a0: 68 32 3e 0a 0a 20 20 20 20 3c 21 2d 2d 20 49 6e h2>.. <!-- In
23b0: 64 69 65 41 75 74 68 20 2d 2d 3e 0a 20 20 20 20 dieAuth -->.
23c0: 3c 70 3e 3c 62 3e 7b 24 68 28 24 63 6c 69 65 6e <p><b>{$h($clien
23d0: 74 5f 69 64 29 7d 3c 2f 62 3e 20 68 61 73 20 72 t_id)}</b> has r
23e0: 65 71 75 65 73 74 65 64 20 6c 6f 67 69 6e 20 76 equested login v
23f0: 65 72 69 66 69 63 61 74 69 6f 6e 20 66 6f 72 20 erification for
2400: 3c 65 6d 3e 7b 24 68 28 24 6d 65 29 7d 3c 2f 65 <em>{$h($me)}</e
2410: 6d 3e 2e 3c 2f 70 3e 0a 20 20 20 20 3c 66 6f 72 m>.</p>. <for
2420: 6d 20 61 63 74 69 6f 6e 3d 27 24 5f 53 45 52 56 m action='$_SERV
2430: 45 52 5b 50 48 50 5f 53 45 4c 46 5d 27 20 6d 65 ER[PHP_SELF]' me
2440: 74 68 6f 64 3d 50 4f 53 54 3e 0a 20 20 20 20 20 thod=POST>.
2450: 20 3c 75 6c 20 73 74 79 6c 65 3d 22 64 69 73 70 <ul style="disp
2460: 6c 61 79 3a 20 66 6c 65 78 3b 20 66 6c 65 78 2d lay: flex; flex-
2470: 77 72 61 70 3a 20 77 72 61 70 22 3e 0a 20 20 20 wrap: wrap">.
2480: 20 20 20 20 20 20 24 73 63 6f 70 65 0a 20 20 20 $scope.
2490: 20 20 20 3c 2f 75 6c 3e 0a 20 20 20 20 20 20 3c </ul>. <
24a0: 70 3e 0a 20 20 20 20 20 20 20 20 3c 69 6e 70 75 p>. <inpu
24b0: 74 20 74 79 70 65 3d 68 69 64 64 65 6e 20 6e 61 t type=hidden na
24c0: 6d 65 3d 63 6f 64 65 20 76 61 6c 75 65 3d 27 7b me=code value='{
24d0: 24 68 28 24 63 6f 64 65 29 7d 27 3e 0a 20 20 20 $h($code)}'>.
24e0: 20 20 20 20 20 3c 69 6e 70 75 74 20 74 79 70 65 <input type
24f0: 3d 68 69 64 64 65 6e 20 6e 61 6d 65 3d 72 65 64 =hidden name=red
2500: 69 72 65 63 74 5f 74 61 72 67 65 74 20 76 61 6c irect_target val
2510: 75 65 3d 27 7b 24 68 28 24 75 72 6c 29 7d 27 3e ue='{$h($url)}'>
2520: 0a 20 20 20 20 20 20 20 20 3c 69 6e 70 75 74 20 . <input
2530: 74 79 70 65 3d 73 75 62 6d 69 74 20 6e 61 6d 65 type=submit name
2540: 3d 63 6f 6e 66 69 72 6d 20 76 61 6c 75 65 3d 43 =confirm value=C
2550: 6f 6e 66 69 72 6d 20 73 74 79 6c 65 3d 27 62 6f onfirm style='bo
2560: 72 64 65 72 2d 72 61 64 69 75 73 3a 20 35 70 74 rder-radius: 5pt
2570: 3b 20 70 61 64 64 69 6e 67 3a 20 35 70 74 20 32 ; padding: 5pt 2
2580: 35 70 74 3b 20 74 65 78 74 2d 73 68 61 64 6f 77 5pt; text-shadow
2590: 3a 20 31 70 74 3b 27 3e 0a 20 20 20 20 20 20 3c : 1pt;'>. <
25a0: 2f 70 3e 0a 20 20 20 20 3c 2f 66 6f 72 6d 3e 0a /p>. </form>.
25b0: 0a 48 54 4d 4c 3b 0a 20 20 20 20 70 61 67 65 5f .HTML;. page_
25c0: 68 74 6d 6c 28 24 68 74 6d 6c 29 3b 0a 7d 0a 0a html($html);.}..
25d0: 23 2d 2d 20 63 6f 6e 66 69 72 6d 20 62 75 74 74 #-- confirm butt
25e0: 6f 6e 20 70 72 65 73 73 65 64 2c 20 64 6f 20 74 on pressed, do t
25f0: 68 65 20 61 63 74 75 61 6c 20 72 65 64 69 72 65 he actual redire
2600: 63 74 0a 66 75 6e 63 74 69 6f 6e 20 63 6f 6e 66 ct.function conf
2610: 69 72 6d 28 29 20 7b 0a 20 20 20 20 69 66 20 28 irm() {. if (
2620: 21 65 6d 70 74 79 28 24 5f 50 4f 53 54 5b 22 73 !empty($_POST["s
2630: 63 6f 70 65 22 5d 29 29 20 7b 0a 20 20 20 20 20 cope"])) {.
2640: 20 20 20 64 62 28 22 55 50 44 41 54 45 20 66 78 db("UPDATE fx
2650: 5f 61 75 74 68 20 53 45 54 20 73 63 6f 70 65 3d _auth SET scope=
2660: 3f 20 57 48 45 52 45 20 63 6f 64 65 3d 3f 22 2c ? WHERE code=?",
2670: 20 5b 20 20 69 6d 70 6c 6f 64 65 28 22 20 22 2c [ implode(" ",
2680: 20 24 5f 50 4f 53 54 5b 22 73 63 6f 70 65 22 5d $_POST["scope"]
2690: 29 2c 20 20 24 5f 50 4f 53 54 5b 22 63 6f 64 65 ), $_POST["code
26a0: 22 5d 20 20 5d 29 3b 0a 20 20 20 20 7d 0a 20 20 "] ]);. }.
26b0: 20 20 64 69 65 28 68 65 61 64 65 72 28 22 4c 6f die(header("Lo
26c0: 63 61 74 69 6f 6e 3a 20 24 5f 50 4f 53 54 5b 72 cation: $_POST[r
26d0: 65 64 69 72 65 63 74 5f 74 61 72 67 65 74 5d 22 edirect_target]"
26e0: 29 29 3b 0a 7d 0a 0a 0a 23 2d 2d 20 73 65 6e 64 ));.}...#-- send
26f0: 20 3f 63 6f 64 65 3d 20 76 65 72 69 66 69 63 61 ?code= verifica
2700: 74 69 6f 6e 20 72 65 73 70 6f 6e 73 65 0a 66 75 tion response.fu
2710: 6e 63 74 69 6f 6e 20 76 65 72 69 66 79 5f 63 6f nction verify_co
2720: 64 65 28 29 20 7b 0a 20 20 20 20 68 65 61 64 65 de() {. heade
2730: 72 28 22 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a r("Content-Type:
2740: 20 61 70 70 6c 69 63 61 74 69 6f 6e 2f 6a 73 6f application/jso
2750: 6e 22 29 3b 0a 0a 20 20 20 20 23 20 69 6e 70 75 n");.. # inpu
2760: 74 0a 20 20 20 20 24 67 72 61 6e 74 5f 74 79 70 t. $grant_typ
2770: 65 20 3d 20 24 5f 52 45 51 55 45 53 54 5b 22 67 e = $_REQUEST["g
2780: 72 61 6e 74 5f 74 79 70 65 22 5d 3b 0a 20 20 20 rant_type"];.
2790: 20 24 63 6f 64 65 20 3d 20 24 5f 52 45 51 55 45 $code = $_REQUE
27a0: 53 54 5b 22 63 6f 64 65 22 5d 3b 0a 20 20 20 20 ST["code"];.
27b0: 24 63 6c 69 65 6e 74 5f 69 64 20 3d 20 24 5f 52 $client_id = $_R
27c0: 45 51 55 45 53 54 5b 22 63 6c 69 65 6e 74 5f 69 EQUEST["client_i
27d0: 64 22 5d 3b 0a 20 20 20 20 24 72 65 64 69 72 65 d"];. $redire
27e0: 63 74 5f 75 72 69 20 3d 20 24 5f 52 45 51 55 45 ct_uri = $_REQUE
27f0: 53 54 5b 22 72 65 64 69 72 65 63 74 5f 75 72 69 ST["redirect_uri
2800: 22 5d 3b 0a 20 20 20 20 24 63 6f 64 65 5f 76 65 "];. $code_ve
2810: 72 69 66 69 65 72 20 3d 20 24 5f 52 45 51 55 45 rifier = $_REQUE
2820: 53 54 5b 22 63 6f 64 65 5f 76 65 72 69 66 69 65 ST["code_verifie
2830: 72 22 5d 3b 0a 20 20 20 20 0a 20 20 20 20 23 20 r"];. . #
2840: 66 69 6e 64 20 74 6f 6b 65 6e 0a 20 20 20 20 63 find token. c
2850: 6c 65 61 6e 5f 65 78 70 69 72 65 64 5f 74 6f 6b lean_expired_tok
2860: 65 6e 28 29 3b 0a 20 20 20 20 24 74 6f 6b 65 6e en();. $token
2870: 20 3d 20 67 65 74 5f 74 6f 6b 65 6e 5f 62 79 5f = get_token_by_
2880: 63 6f 64 65 28 24 63 6f 64 65 29 5b 30 5d 3b 0a code($code)[0];.
2890: 20 20 20 20 24 63 6f 64 65 5f 63 68 61 6c 6c 65 $code_challe
28a0: 6e 67 65 20 3d 20 24 74 6f 6b 65 6e 5b 22 63 6f nge = $token["co
28b0: 64 65 5f 63 68 61 6c 6c 65 6e 67 65 22 5d 3b 0a de_challenge"];.
28c0: 20 20 20 20 0a 20 20 20 20 23 20 63 68 65 63 6b . # check
28d0: 20 70 61 72 61 6d 73 0a 20 20 20 20 69 66 20 28 params. if (
28e0: 65 6d 70 74 79 28 24 63 6f 64 65 29 20 6f 72 20 empty($code) or
28f0: 65 6d 70 74 79 28 24 63 6c 69 65 6e 74 5f 69 64 empty($client_id
2900: 29 20 6f 72 20 65 6d 70 74 79 28 24 72 65 64 69 ) or empty($redi
2910: 72 65 63 74 5f 75 72 69 29 29 20 7b 0a 20 20 20 rect_uri)) {.
2920: 20 20 20 20 20 24 6c 73 20 3d 20 6a 6f 69 6e 28 $ls = join(
2930: 22 2c 20 22 2c 20 61 72 72 61 79 5f 64 69 66 66 ", ", array_diff
2940: 28 5b 22 63 6f 64 65 22 2c 20 22 63 6c 69 65 6e (["code", "clien
2950: 74 5f 69 64 22 2c 20 22 72 65 64 69 72 65 63 74 t_id", "redirect
2960: 5f 75 72 69 22 5d 2c 20 61 72 72 61 79 5f 6b 65 _uri"], array_ke
2970: 79 73 28 24 5f 52 45 51 55 45 53 54 29 29 29 3b ys($_REQUEST)));
2980: 0a 20 20 20 20 20 20 20 20 64 69 65 28 6a 73 6f . die(jso
2990: 6e 5f 65 6e 63 6f 64 65 28 5b 22 65 72 72 6f 72 n_encode(["error
29a0: 22 20 3d 3e 20 20 22 69 6e 76 61 6c 69 64 5f 72 " => "invalid_r
29b0: 65 71 75 65 73 74 22 2c 20 22 65 72 72 6f 72 5f equest", "error_
29c0: 64 65 73 63 72 69 70 74 69 6f 6e 22 20 3d 3e 20 description" =>
29d0: 22 6d 69 73 73 69 6e 67 20 70 61 72 61 6d 65 74 "missing paramet
29e0: 65 72 73 20 28 24 6c 73 29 22 5d 29 29 3b 0a 20 ers ($ls)"]));.
29f0: 20 20 20 7d 0a 20 20 20 20 65 6c 73 65 69 66 20 }. elseif
2a00: 28 65 6d 70 74 79 28 24 74 6f 6b 65 6e 29 29 20 (empty($token))
2a10: 7b 0a 20 20 20 20 20 20 20 20 64 69 65 28 6a 73 {. die(js
2a20: 6f 6e 5f 65 6e 63 6f 64 65 28 5b 22 65 72 72 6f on_encode(["erro
2a30: 72 22 20 3d 3e 20 20 22 61 63 63 65 73 73 5f 64 r" => "access_d
2a40: 65 6e 69 65 64 22 2c 20 22 65 72 72 6f 72 5f 64 enied", "error_d
2a50: 65 73 63 72 69 70 74 69 6f 6e 22 20 3d 3e 20 22 escription" => "
2a60: 63 6f 64 65 20 27 24 63 6f 64 65 27 20 64 6f 65 code '$code' doe
2a70: 73 20 6e 6f 74 20 65 78 69 73 74 20 28 70 6f 73 s not exist (pos
2a80: 73 69 62 6c 79 20 65 78 70 69 72 65 64 29 22 5d sibly expired)"]
2a90: 29 29 3b 0a 20 20 20 20 7d 0a 20 20 20 20 65 6c ));. }. el
2aa0: 73 65 69 66 20 28 28 24 74 6f 6b 65 6e 5b 22 63 seif (($token["c
2ab0: 6c 69 65 6e 74 5f 69 64 22 5d 20 21 3d 20 24 63 lient_id"] != $c
2ac0: 6c 69 65 6e 74 5f 69 64 29 20 6f 72 20 28 24 74 lient_id) or ($t
2ad0: 6f 6b 65 6e 5b 22 72 65 64 69 72 65 63 74 5f 75 oken["redirect_u
2ae0: 72 69 22 5d 20 21 3d 20 24 72 65 64 69 72 65 63 ri"] != $redirec
2af0: 74 5f 75 72 69 29 29 20 7b 0a 20 20 20 20 20 20 t_uri)) {.
2b00: 20 20 64 69 65 28 6a 73 6f 6e 5f 65 6e 63 6f 64 die(json_encod
2b10: 65 28 5b 22 65 72 72 6f 72 22 20 3d 3e 20 20 22 e(["error" => "
2b20: 69 6e 76 61 6c 69 64 5f 73 63 6f 70 65 22 2c 20 invalid_scope",
2b30: 22 65 72 72 6f 72 5f 64 65 73 63 72 69 70 74 69 "error_descripti
2b40: 6f 6e 22 20 3d 3e 20 22 63 6f 64 65 20 64 6f 65 on" => "code doe
2b50: 73 20 6e 6f 74 20 6d 61 74 63 68 20 70 72 65 76 s not match prev
2b60: 69 6f 75 73 20 70 61 72 61 6d 73 20 28 63 6c 69 ious params (cli
2b70: 65 6e 74 5f 69 64 2c 20 72 65 64 69 72 65 63 74 ent_id, redirect
2b80: 5f 75 72 69 29 22 5d 29 29 3b 0a 20 20 20 20 7d _uri)"]));. }
2b90: 0a 20 20 20 20 65 6c 73 65 69 66 20 28 24 63 6f . elseif ($co
2ba0: 64 65 5f 63 68 61 6c 6c 65 6e 67 65 20 61 6e 64 de_challenge and
2bb0: 20 62 61 73 65 36 34 5f 75 72 6c 65 6e 63 6f 64 base64_urlencod
2bc0: 65 28 68 61 73 68 28 22 73 68 61 32 35 36 22 2c e(hash("sha256",
2bd0: 20 24 63 6f 64 65 5f 76 65 72 69 66 69 65 72 2c $code_verifier,
2be0: 20 31 29 29 20 21 3d 20 24 63 6f 64 65 5f 63 68 1)) != $code_ch
2bf0: 61 6c 6c 65 6e 67 65 29 20 7b 0a 20 20 20 20 20 allenge) {.
2c00: 20 20 20 64 69 65 28 6a 73 6f 6e 5f 65 6e 63 6f die(json_enco
2c10: 64 65 28 5b 22 65 72 72 6f 72 22 20 3d 3e 20 20 de(["error" =>
2c20: 22 75 6e 61 75 74 68 6f 72 69 7a 65 64 5f 63 6c "unauthorized_cl
2c30: 69 65 6e 74 22 2c 20 22 65 72 72 6f 72 5f 64 65 ient", "error_de
2c40: 73 63 72 69 70 74 69 6f 6e 22 20 3d 3e 20 22 63 scription" => "c
2c50: 6f 64 65 5f 63 68 61 6c 6c 65 6e 67 65 20 64 6f ode_challenge do
2c60: 65 73 20 6e 6f 74 20 6d 61 74 63 68 20 63 6f 64 es not match cod
2c70: 65 5f 76 65 72 69 66 69 65 72 22 5d 29 29 3b 0a e_verifier"]));.
2c80: 20 20 20 20 7d 0a 20 20 20 20 65 6c 73 65 20 7b }. else {
2c90: 0a 20 20 20 20 20 20 20 20 23 20 61 70 70 72 6f . # appro
2ca0: 76 65 64 0a 20 20 20 20 20 20 20 20 64 69 65 28 ved. die(
2cb0: 6a 73 6f 6e 5f 65 6e 63 6f 64 65 28 5b 22 6d 65 json_encode(["me
2cc0: 22 20 3d 3e 20 24 74 6f 6b 65 6e 5b 22 6d 65 22 " => $token["me"
2cd0: 5d 2c 20 22 73 63 6f 70 65 22 20 3d 3e 20 24 74 ], "scope" => $t
2ce0: 6f 6b 65 6e 5b 22 73 63 6f 70 65 22 5d 5d 29 29 oken["scope"]]))
2cf0: 3b 0a 20 20 20 20 7d 0a 7d 0a 0a 0a 23 2d 2d 20 ;. }.}...#--
2d00: 72 75 6e 0a 69 66 20 28 65 6d 70 74 79 28 24 5f run.if (empty($_
2d10: 50 4f 53 54 5b 22 72 65 64 69 72 65 63 74 5f 74 POST["redirect_t
2d20: 61 72 67 65 74 22 5d 29 20 61 6e 64 20 21 65 6d arget"]) and !em
2d30: 70 74 79 28 24 5f 52 45 51 55 45 53 54 5b 22 63 pty($_REQUEST["c
2d40: 6f 64 65 22 5d 29 29 20 7b 20 20 23 20 3f 63 6f ode"])) { # ?co
2d50: 64 65 3d e2 80 a6 20 77 68 65 6e 20 74 68 65 20 de=โฆ when the
2d60: 72 65 6d 6f 74 65 20 61 70 70 20 76 65 72 69 66 remote app verif
2d70: 69 65 73 20 74 68 65 20 72 65 73 70 6f 6e 73 65 ies the response
2d80: 0a 20 20 20 20 76 65 72 69 66 79 5f 63 6f 64 65 . verify_code
2d90: 28 29 3b 0a 7d 0a 65 6c 73 65 69 66 20 28 65 6d ();.}.elseif (em
2da0: 70 74 79 28 24 5f 53 45 52 56 45 52 5b 22 46 4f pty($_SERVER["FO
2db0: 53 53 49 4c 5f 55 53 45 52 22 5d 29 29 20 7b 20 SSIL_USER"])) {
2dc0: 20 20 23 20 75 73 65 72 20 6d 75 73 74 20 62 65 # user must be
2dd0: 20 73 69 67 6e 65 64 20 69 6e 20 61 74 20 74 68 signed in at th
2de0: 69 73 20 70 6f 69 6e 74 0a 20 20 20 20 70 61 67 is point. pag
2df0: 65 5f 68 74 6d 6c 28 22 3c 68 32 3e 4e 6f 74 20 e_html("<h2>Not
2e00: 6c 6f 67 67 65 64 20 69 6e 3c 2f 68 32 3e 5c 6e logged in</h2>\n
2e10: 20 52 65 71 75 65 73 74 20 63 61 6e 27 74 20 62 Request can't b
2e20: 65 20 61 75 74 68 6f 72 69 7a 65 64 2c 20 75 6e e authorized, un
2e30: 6c 65 73 73 20 79 6f 75 27 72 65 20 3c 61 20 68 less you're <a h
2e40: 72 65 66 3d 27 2e 2e 2f 6c 6f 67 69 6e 27 3e 6c ref='../login'>l
2e50: 6f 67 67 65 64 20 69 6e 3c 2f 61 3e 2e 22 29 3b ogged in</a>.");
2e60: 0a 7d 0a 65 6c 73 65 69 66 20 28 21 65 6d 70 74 .}.elseif (!empt
2e70: 79 28 24 5f 52 45 51 55 45 53 54 5b 22 6d 65 22 y($_REQUEST["me"
2e80: 5d 29 29 20 7b 20 20 20 23 20 3f 6d 65 3d e2 80 ])) { # ?me=โ
2e90: a6 20 73 74 61 72 74 73 20 61 6e 20 61 75 74 68 ฆ starts an auth
2ea0: 6f 72 69 7a 61 74 69 6f 6e 20 72 65 71 75 65 73 orization reques
2eb0: 74 0a 20 20 20 20 70 72 6f 63 65 73 73 5f 72 65 t. process_re
2ec0: 71 75 65 73 74 28 29 3b 0a 7d 0a 65 6c 73 65 69 quest();.}.elsei
2ed0: 66 20 28 21 65 6d 70 74 79 28 24 5f 50 4f 53 54 f (!empty($_POST
2ee0: 5b 22 63 6f 6e 66 69 72 6d 22 5d 29 29 20 7b 20 ["confirm"])) {
2ef0: 20 20 23 20 3f 72 65 64 69 72 65 63 74 5f 74 61 # ?redirect_ta
2f00: 72 67 65 74 3d e2 80 a6 20 20 66 6f 72 20 63 6f rget=โฆ for co
2f10: 6e 66 69 72 6d 61 74 69 6f 6e 20 62 75 74 74 6f nfirmation butto
2f20: 6e 0a 20 20 20 20 63 6f 6e 66 69 72 6d 28 29 3b n. confirm();
2f30: 0a 7d 0a 65 6c 73 65 20 7b 0a 20 20 20 20 63 72 .}.else {. cr
2f40: 65 61 74 65 5f 74 61 62 6c 65 28 29 3b 0a 20 20 eate_table();.
2f50: 20 20 70 61 67 65 5f 68 74 6d 6c 28 22 0a 20 20 page_html(".
2f60: 20 20 20 20 20 3c 68 33 3e 41 75 74 68 6f 72 69 <h3>Authori
2f70: 7a 61 74 69 6f 6e 20 65 6e 64 70 6f 69 6e 74 3c zation endpoint<
2f80: 2f 68 33 3e 0a 20 20 20 20 20 20 20 54 68 65 72 /h3>. Ther
2f90: 65 20 77 61 73 20 6e 6f 20 3f 63 6f 64 65 3d 20 e was no ?code=
2fa0: 6f 72 20 3f 6d 65 3d 20 70 61 72 61 6d 65 74 65 or ?me= paramete
2fb0: 72 2c 3c 62 72 3e 20 73 6f 20 6e 6f 74 20 61 6e r,<br> so not an
2fc0: 20 61 63 74 75 61 6c 20 49 6e 64 69 65 2f 4f 41 actual Indie/OA
2fd0: 75 74 68 20 72 65 71 75 65 73 74 2e 0a 20 20 20 uth request..
2fe0: 20 20 20 20 3c 75 6c 3e 0a 20 20 20 20 20 20 20 <ul>.
2ff0: 20 20 3c 6c 69 3e 54 68 65 20 3c 63 6f 64 65 3e <li>The <code>
3000: 66 78 5f 61 75 74 68 3c 2f 63 6f 64 65 3e 20 74 fx_auth</code> t
3010: 61 62 6c 65 20 69 73 20 6e 6f 77 20 63 6f 6e 66 able is now conf
3020: 69 67 75 72 65 64 2e 0a 20 20 20 20 20 20 20 20 igured..
3030: 20 3c 6c 69 3e 55 73 65 72 73 20 73 74 69 6c 6c <li>Users still
3040: 20 6e 65 65 64 20 74 6f 20 61 64 64 20 74 68 65 need to add the
3050: 69 72 20 68 6f 6d 65 70 61 67 65 20 69 6e 20 74 ir homepage in t
3060: 68 65 20 63 6f 6e 74 61 63 74 2f 60 69 6e 66 6f he contact/`info
3070: 60 20 66 69 65 6c 64 2e 20 28 53 65 65 20 3c 61 ` field. (See <a
3080: 20 68 72 65 66 3d 27 75 73 65 72 5f 63 6f 6e 66 href='user_conf
3090: 69 67 27 3e 65 78 74 2f 75 73 65 72 5f 63 6f 6e ig'>ext/user_con
30a0: 66 69 67 3c 2f 61 3e 2e 29 0a 20 20 20 20 20 20 fig</a>.).
30b0: 20 20 20 3c 6c 69 3e 41 6e 64 20 74 68 65 6e 20 <li>And then
30c0: 64 65 63 6c 61 72 65 20 74 68 69 73 20 65 6e 64 declare this end
30d0: 70 6f 69 6e 74 20 6f 6e 20 74 68 65 69 72 20 70 point on their p
30e0: 65 72 73 6f 6e 61 6c 20 68 6f 6d 65 70 61 67 65 ersonal homepage
30f0: 3a 3c 62 72 3e 0a 20 20 20 20 20 20 20 20 20 20 :<br>.
3100: 20 20 20 3c 63 6f 64 65 3e 26 6c 74 3b 6c 69 6e <code><lin
3110: 6b 20 72 65 6c 3d 61 75 74 68 6f 72 69 7a 61 74 k rel=authorizat
3120: 69 6f 6e 5f 65 6e 64 70 6f 69 6e 74 20 68 72 65 ion_endpoint hre
3130: 66 3d 27 68 74 74 70 73 3a 2f 2f 24 5f 53 45 52 f='https://$_SER
3140: 56 45 52 5b 53 45 52 56 45 52 5f 4e 41 4d 45 5d VER[SERVER_NAME]
3150: 24 5f 53 45 52 56 45 52 5b 50 48 50 5f 53 45 4c $_SERVER[PHP_SEL
3160: 46 5d 27 26 67 74 3b 3c 2f 63 6f 64 65 3e 0a 20 F]'></code>.
3170: 20 20 20 20 20 20 3c 2f 75 6c 3e 0a 20 20 20 20 </ul>.
3180: 22 29 3b 0a 7d 0a 0a 0a 3f 3e ");.}...?>