@@ -704,7 +704,7 @@ func TestAuthCode_CallbackPageReflectsTokenExchangeResult(t *testing.T) {
704704 if err != nil {
705705 t .Fatalf ("OnRequest: %v" , err )
706706 }
707- if body := <- bodyCh ; ! strings .Contains (body , "Authorization code received" ) || ! strings .Contains (body , "Authentication successful " ) {
707+ if body := <- bodyCh ; ! strings .Contains (body , "Login Successful!" ) || ! strings . Contains ( body , `class="check"` ) || ! strings .Contains (body , "@keyframes success-bg " ) {
708708 t .Fatalf ("callback body = %q" , body )
709709 }
710710 })
@@ -740,12 +740,130 @@ func TestAuthCode_CallbackPageReflectsTokenExchangeResult(t *testing.T) {
740740 if err == nil {
741741 t .Fatal ("expected token exchange error" )
742742 }
743- if body := <- bodyCh ; ! strings .Contains (body , "Authorization code received" ) || ! strings .Contains (body , "Authentication failed " ) {
743+ if body := <- bodyCh ; ! strings .Contains (body , "Authentication failed" ) || ! strings . Contains ( body , `class="x"` ) || ! strings .Contains (body , "@keyframes failure-bg " ) {
744744 t .Fatalf ("callback body = %q" , body )
745745 }
746746 })
747747}
748748
749+ func TestOAuthCallbackErrorPageEscapesDetail (t * testing.T ) {
750+ body := oauthCallbackErrorPage ("Authentication failed" , `<script>alert("nope")</script>` , "" )
751+ if strings .Contains (body , "<script>" ) {
752+ t .Fatalf ("callback body includes raw script: %q" , body )
753+ }
754+ if ! strings .Contains (body , `<script>alert("nope")</script>` ) {
755+ t .Fatalf ("callback body does not include escaped detail: %q" , body )
756+ }
757+ }
758+
759+ func TestOAuthCallbackPageUsesConfiguredBackgroundColor (t * testing.T ) {
760+ body := oauthCallbackSuccessPage ("Login Successful!" , "Done." , "#50fa7b" )
761+ if ! strings .Contains (body , "to { background: #50fa7b; }" ) {
762+ t .Fatalf ("callback body does not use configured color: %q" , body )
763+ }
764+ }
765+
766+ func TestOAuthCallbackPageRejectsInvalidBackgroundColor (t * testing.T ) {
767+ body := oauthCallbackErrorPage ("Authentication failed" , "Nope." , `red; background: url("bad")` )
768+ if strings .Contains (body , "url(" ) {
769+ t .Fatalf ("callback body includes invalid CSS color: %q" , body )
770+ }
771+ if ! strings .Contains (body , "to { background: #E94F37; }" ) {
772+ t .Fatalf ("callback body did not fall back to default failure color: %q" , body )
773+ }
774+ }
775+
776+ func TestOAuthCallbackPagesUseCustomHTMLFields (t * testing.T ) {
777+ h := & AuthorizationCode {
778+ CallbackSuccessHTML : `<html><body><h1>Welcome to my-tool</h1></body></html>` ,
779+ CallbackErrorHTML : `<html><body><h1>$ERROR</h1><p>$DETAILS</p></body></html>` ,
780+ }
781+ if got , want := h .oauthCallbackSuccessPage ("Login Successful!" , "Done." ), h .CallbackSuccessHTML ; got != want {
782+ t .Fatalf ("custom success body = %q, want %q" , got , want )
783+ }
784+ got := h .oauthCallbackErrorPage ("Authentication failed" , `<script>alert("nope")</script>` )
785+ want := `<html><body><h1>Authentication failed</h1><p><script>alert("nope")</script></p></body></html>`
786+ if got != want {
787+ t .Fatalf ("custom error body = %q, want %q" , got , want )
788+ }
789+ }
790+
791+ func TestOAuthCallbackPagesUseCustomHTMLParams (t * testing.T ) {
792+ h := & AuthorizationCode {
793+ CallbackSuccessHTML : `<html>field success</html>` ,
794+ CallbackErrorHTML : `<html>field error</html>` ,
795+ }
796+ pages := h .oauthCallbackPages (map [string ]string {
797+ callbackSuccessHTMLParam : `<html><body><h1>$TITLE</h1><p>$DETAILS</p></body></html>` ,
798+ callbackErrorHTMLParam : `<html><body><h1>$ERROR</h1><p>$DETAILS</p></body></html>` ,
799+ })
800+ if got , want := pages .successPage ("Login Successful!" , "Done." ), `<html><body><h1>Login Successful!</h1><p>Done.</p></body></html>` ; got != want {
801+ t .Fatalf ("custom success body = %q, want %q" , got , want )
802+ }
803+ got := pages .errorPage ("Error: access_denied" , `bad <reason>` , "access_denied" )
804+ want := `<html><body><h1>access_denied</h1><p>bad <reason></p></body></html>`
805+ if got != want {
806+ t .Fatalf ("custom error body = %q, want %q" , got , want )
807+ }
808+ }
809+
810+ func TestAuthCode_CustomCallbackHTMLParamsAreNotForwarded (t * testing.T ) {
811+ h := & AuthorizationCode {
812+ HTTPClient : testHTTPClient (func (r * http.Request ) (* http.Response , error ) {
813+ if err := r .ParseForm (); err != nil {
814+ t .Fatalf ("ParseForm: %v" , err )
815+ }
816+ if got := r .FormValue (callbackSuccessHTMLParam ); got != "" {
817+ t .Fatalf ("%s forwarded to token endpoint: %q" , callbackSuccessHTMLParam , got )
818+ }
819+ if got := r .FormValue (callbackErrorHTMLParam ); got != "" {
820+ t .Fatalf ("%s forwarded to token endpoint: %q" , callbackErrorHTMLParam , got )
821+ }
822+ return testResponse (200 , "application/json" , `{"access_token":"custom-html-token","token_type":"bearer","expires_in":3600}` ), nil
823+ }),
824+ OpenBrowser : func (raw string ) error {
825+ go func () {
826+ authorizeURL , err := url .Parse (raw )
827+ if err != nil {
828+ t .Errorf ("parse authorize URL: %v" , err )
829+ return
830+ }
831+ if got := authorizeURL .Query ().Get (callbackSuccessHTMLParam ); got != "" {
832+ t .Errorf ("%s forwarded to authorize endpoint: %q" , callbackSuccessHTMLParam , got )
833+ return
834+ }
835+ if got := authorizeURL .Query ().Get (callbackErrorHTMLParam ); got != "" {
836+ t .Errorf ("%s forwarded to authorize endpoint: %q" , callbackErrorHTMLParam , got )
837+ return
838+ }
839+ callbackURL , state := mustCallbackURL (t , raw )
840+ resp , err := http .Get (fmt .Sprintf ("%s/?state=%s&code=good-code" , callbackURL , url .QueryEscape (state )))
841+ if err != nil {
842+ t .Errorf ("callback request failed: %v" , err )
843+ return
844+ }
845+ resp .Body .Close ()
846+ }()
847+ return nil
848+ },
849+ }
850+ req , _ := http .NewRequest ("GET" , "https://api.example.com" , nil )
851+ err := h .OnRequest (req , map [string ]string {
852+ "client_id" : "id1" ,
853+ "authorize_url" : "https://auth.example.com/authorize" ,
854+ "token_url" : "https://auth.example.com/token" ,
855+ "redirect_port" : availablePort (t ),
856+ callbackSuccessHTMLParam : `<html>success</html>` ,
857+ callbackErrorHTMLParam : `<html>error</html>` ,
858+ })
859+ if err != nil {
860+ t .Fatalf ("OnRequest: %v" , err )
861+ }
862+ if got := req .Header .Get ("Authorization" ); got != "Bearer custom-html-token" {
863+ t .Fatalf ("Authorization = %q, want custom HTML token" , got )
864+ }
865+ }
866+
749867func TestAuthCode_ManualCodeFallback (t * testing.T ) {
750868 var stderr bytes.Buffer
751869 h := & AuthorizationCode {
0 commit comments