mirror of
				https://github.com/ergochat/ergo.git
				synced 2025-11-04 07:47:25 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			67 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			67 lines
		
	
	
		
			1.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) 2024 Shivaram Lingamneni <slingamn@cs.stanford.edu>
 | 
						|
// Released under the MIT license
 | 
						|
// Some portions of this code are:
 | 
						|
// Copyright (c) 2024 Simon Ser <contact@emersion.fr>
 | 
						|
// Originally released under the AGPLv3, relicensed to the Ergo project under the MIT license
 | 
						|
 | 
						|
package webpush
 | 
						|
 | 
						|
import (
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"net"
 | 
						|
	"net/http"
 | 
						|
	"net/netip"
 | 
						|
	"net/url"
 | 
						|
	"syscall"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	errInternalIP = errors.New("dialing an internal IP is forbidden")
 | 
						|
)
 | 
						|
 | 
						|
func SanityCheckWebPushEndpoint(endpoint string) error {
 | 
						|
	u, err := url.Parse(endpoint)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if u.Scheme != "https" {
 | 
						|
		return fmt.Errorf("scheme must be HTTPS")
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// makeExternalOnlyClient builds an http.Client that can only connect
 | 
						|
// to external IP addresses.
 | 
						|
func makeExternalOnlyClient() *http.Client {
 | 
						|
	dialer := &net.Dialer{
 | 
						|
		Control: func(network, address string, c syscall.RawConn) error {
 | 
						|
			ip, _, err := net.SplitHostPort(address)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			parsedIP, err := netip.ParseAddr(ip)
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
 | 
						|
			if isInternalIP(parsedIP) {
 | 
						|
				return errInternalIP
 | 
						|
			}
 | 
						|
 | 
						|
			return nil
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	return &http.Client{
 | 
						|
		Transport: &http.Transport{
 | 
						|
			DialContext: dialer.DialContext,
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func isInternalIP(ip netip.Addr) bool {
 | 
						|
	return ip.IsLoopback() || ip.IsMulticast() || ip.IsPrivate()
 | 
						|
}
 |