mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 12:26:05 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			123 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2022 The Gitea Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package web
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	user_model "code.gitea.io/gitea/models/user"
 | 
						|
	"code.gitea.io/gitea/modules/log"
 | 
						|
	"code.gitea.io/gitea/modules/setting"
 | 
						|
	"code.gitea.io/gitea/services/context"
 | 
						|
)
 | 
						|
 | 
						|
// https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-webfinger-14#section-4.4
 | 
						|
 | 
						|
type webfingerJRD struct {
 | 
						|
	Subject    string           `json:"subject,omitempty"`
 | 
						|
	Aliases    []string         `json:"aliases,omitempty"`
 | 
						|
	Properties map[string]any   `json:"properties,omitempty"`
 | 
						|
	Links      []*webfingerLink `json:"links,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
type webfingerLink struct {
 | 
						|
	Rel        string            `json:"rel,omitempty"`
 | 
						|
	Type       string            `json:"type,omitempty"`
 | 
						|
	Href       string            `json:"href,omitempty"`
 | 
						|
	Titles     map[string]string `json:"titles,omitempty"`
 | 
						|
	Properties map[string]any    `json:"properties,omitempty"`
 | 
						|
}
 | 
						|
 | 
						|
// WebfingerQuery returns information about a resource
 | 
						|
// https://datatracker.ietf.org/doc/html/rfc7565
 | 
						|
func WebfingerQuery(ctx *context.Context) {
 | 
						|
	appURL, _ := url.Parse(setting.AppURL)
 | 
						|
 | 
						|
	resource, err := url.Parse(ctx.FormTrim("resource"))
 | 
						|
	if err != nil {
 | 
						|
		ctx.HTTPError(http.StatusBadRequest)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	var u *user_model.User
 | 
						|
 | 
						|
	switch resource.Scheme {
 | 
						|
	case "acct":
 | 
						|
		// allow only the current host
 | 
						|
		parts := strings.SplitN(resource.Opaque, "@", 2)
 | 
						|
		if len(parts) != 2 {
 | 
						|
			ctx.HTTPError(http.StatusBadRequest)
 | 
						|
			return
 | 
						|
		}
 | 
						|
		if parts[1] != appURL.Host {
 | 
						|
			ctx.HTTPError(http.StatusBadRequest)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		u, err = user_model.GetUserByName(ctx, parts[0])
 | 
						|
	case "mailto":
 | 
						|
		u, err = user_model.GetUserByEmail(ctx, resource.Opaque)
 | 
						|
		if u != nil && u.KeepEmailPrivate {
 | 
						|
			err = user_model.ErrUserNotExist{}
 | 
						|
		}
 | 
						|
	default:
 | 
						|
		ctx.HTTPError(http.StatusBadRequest)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if err != nil {
 | 
						|
		if user_model.IsErrUserNotExist(err) {
 | 
						|
			ctx.HTTPError(http.StatusNotFound)
 | 
						|
		} else {
 | 
						|
			log.Error("Error getting user: %s Error: %v", resource.Opaque, err)
 | 
						|
			ctx.HTTPError(http.StatusInternalServerError)
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if !user_model.IsUserVisibleToViewer(ctx, u, ctx.Doer) {
 | 
						|
		ctx.HTTPError(http.StatusNotFound)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	aliases := []string{
 | 
						|
		u.HTMLURL(ctx),
 | 
						|
		appURL.String() + "api/v1/activitypub/user-id/" + strconv.FormatInt(u.ID, 10),
 | 
						|
	}
 | 
						|
	if !u.KeepEmailPrivate {
 | 
						|
		aliases = append(aliases, "mailto:"+u.Email)
 | 
						|
	}
 | 
						|
 | 
						|
	links := []*webfingerLink{
 | 
						|
		{
 | 
						|
			Rel:  "http://webfinger.net/rel/profile-page",
 | 
						|
			Type: "text/html",
 | 
						|
			Href: u.HTMLURL(ctx),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			Rel:  "http://webfinger.net/rel/avatar",
 | 
						|
			Href: u.AvatarLink(ctx),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			Rel:  "self",
 | 
						|
			Type: "application/activity+json",
 | 
						|
			Href: appURL.String() + "api/v1/activitypub/user-id/" + strconv.FormatInt(u.ID, 10),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			Rel:  "http://openid.net/specs/connect/1.0/issuer",
 | 
						|
			Href: appURL.String(),
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	ctx.Resp.Header().Add("Access-Control-Allow-Origin", "*")
 | 
						|
	ctx.JSON(http.StatusOK, &webfingerJRD{
 | 
						|
		Subject: fmt.Sprintf("acct:%s@%s", url.QueryEscape(u.Name), appURL.Host),
 | 
						|
		Aliases: aliases,
 | 
						|
		Links:   links,
 | 
						|
	})
 | 
						|
}
 |