-
Notifications
You must be signed in to change notification settings - Fork 184
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #174 from tobychui/v3.0.5
- Optimized uptime monitor error message - Optimized detection logic for internal proxy target and header rewrite condition for HTTP_HOST - Fixed ovh DNS challenge provider form generator bug - Configuration for OVH DNS Challenge - Added permission policy module (not enabled) - Added single-use cookiejar to uptime monitor request client to handle cookie issues on some poorly written back-end server
- Loading branch information
Showing
10 changed files
with
462 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
193 changes: 193 additions & 0 deletions
193
src/mod/dynamicproxy/permissionpolicy/permissionpolicy.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package permissionpolicy | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
) | ||
|
||
/* | ||
Permisson Policy | ||
This is a permission policy header modifier that changes | ||
the request permission related policy fields | ||
author: tobychui | ||
*/ | ||
|
||
type PermissionsPolicy struct { | ||
Accelerometer []string `json:"accelerometer"` | ||
AmbientLightSensor []string `json:"ambient_light_sensor"` | ||
Autoplay []string `json:"autoplay"` | ||
Battery []string `json:"battery"` | ||
Camera []string `json:"camera"` | ||
CrossOriginIsolated []string `json:"cross_origin_isolated"` | ||
DisplayCapture []string `json:"display_capture"` | ||
DocumentDomain []string `json:"document_domain"` | ||
EncryptedMedia []string `json:"encrypted_media"` | ||
ExecutionWhileNotRendered []string `json:"execution_while_not_rendered"` | ||
ExecutionWhileOutOfView []string `json:"execution_while_out_of_viewport"` | ||
Fullscreen []string `json:"fullscreen"` | ||
Geolocation []string `json:"geolocation"` | ||
Gyroscope []string `json:"gyroscope"` | ||
KeyboardMap []string `json:"keyboard_map"` | ||
Magnetometer []string `json:"magnetometer"` | ||
Microphone []string `json:"microphone"` | ||
Midi []string `json:"midi"` | ||
NavigationOverride []string `json:"navigation_override"` | ||
Payment []string `json:"payment"` | ||
PictureInPicture []string `json:"picture_in_picture"` | ||
PublicKeyCredentialsGet []string `json:"publickey_credentials_get"` | ||
ScreenWakeLock []string `json:"screen_wake_lock"` | ||
SyncXHR []string `json:"sync_xhr"` | ||
USB []string `json:"usb"` | ||
WebShare []string `json:"web_share"` | ||
XRSpatialTracking []string `json:"xr_spatial_tracking"` | ||
ClipboardRead []string `json:"clipboard_read"` | ||
ClipboardWrite []string `json:"clipboard_write"` | ||
Gamepad []string `json:"gamepad"` | ||
SpeakerSelection []string `json:"speaker_selection"` | ||
ConversionMeasurement []string `json:"conversion_measurement"` | ||
FocusWithoutUserActivation []string `json:"focus_without_user_activation"` | ||
HID []string `json:"hid"` | ||
IdleDetection []string `json:"idle_detection"` | ||
InterestCohort []string `json:"interest_cohort"` | ||
Serial []string `json:"serial"` | ||
SyncScript []string `json:"sync_script"` | ||
TrustTokenRedemption []string `json:"trust_token_redemption"` | ||
Unload []string `json:"unload"` | ||
WindowPlacement []string `json:"window_placement"` | ||
VerticalScroll []string `json:"vertical_scroll"` | ||
} | ||
|
||
// GetDefaultPermissionPolicy returns a PermissionsPolicy struct with all policies set to * | ||
func GetDefaultPermissionPolicy() *PermissionsPolicy { | ||
return &PermissionsPolicy{ | ||
Accelerometer: []string{"*"}, | ||
AmbientLightSensor: []string{"*"}, | ||
Autoplay: []string{"*"}, | ||
Battery: []string{"*"}, | ||
Camera: []string{"*"}, | ||
CrossOriginIsolated: []string{"*"}, | ||
DisplayCapture: []string{"*"}, | ||
DocumentDomain: []string{"*"}, | ||
EncryptedMedia: []string{"*"}, | ||
ExecutionWhileNotRendered: []string{"*"}, | ||
ExecutionWhileOutOfView: []string{"*"}, | ||
Fullscreen: []string{"*"}, | ||
Geolocation: []string{"*"}, | ||
Gyroscope: []string{"*"}, | ||
KeyboardMap: []string{"*"}, | ||
Magnetometer: []string{"*"}, | ||
Microphone: []string{"*"}, | ||
Midi: []string{"*"}, | ||
NavigationOverride: []string{"*"}, | ||
Payment: []string{"*"}, | ||
PictureInPicture: []string{"*"}, | ||
PublicKeyCredentialsGet: []string{"*"}, | ||
ScreenWakeLock: []string{"*"}, | ||
SyncXHR: []string{"*"}, | ||
USB: []string{"*"}, | ||
WebShare: []string{"*"}, | ||
XRSpatialTracking: []string{"*"}, | ||
ClipboardRead: []string{"*"}, | ||
ClipboardWrite: []string{"*"}, | ||
Gamepad: []string{"*"}, | ||
SpeakerSelection: []string{"*"}, | ||
ConversionMeasurement: []string{"*"}, | ||
FocusWithoutUserActivation: []string{"*"}, | ||
HID: []string{"*"}, | ||
IdleDetection: []string{"*"}, | ||
InterestCohort: []string{"*"}, | ||
Serial: []string{"*"}, | ||
SyncScript: []string{"*"}, | ||
TrustTokenRedemption: []string{"*"}, | ||
Unload: []string{"*"}, | ||
WindowPlacement: []string{"*"}, | ||
VerticalScroll: []string{"*"}, | ||
} | ||
} | ||
|
||
// InjectPermissionPolicyHeader inject the permission policy into headers | ||
func InjectPermissionPolicyHeader(w http.ResponseWriter, policy *PermissionsPolicy) { | ||
//Keep the original Permission Policy if exists, or there are no policy given | ||
if policy == nil || w.Header().Get("Permissions-Policy") != "" { | ||
return | ||
} | ||
|
||
policyHeader := []string{} | ||
|
||
// Helper function to add policy directives | ||
addDirective := func(name string, sources []string) { | ||
if len(sources) > 0 { | ||
if sources[0] == "*" { | ||
//Allow all | ||
policyHeader = append(policyHeader, fmt.Sprintf("%s=%s", name, "*")) | ||
} else { | ||
//Other than "self" which do not need double quote, others domain need double quote in place | ||
formatedSources := []string{} | ||
for _, source := range sources { | ||
if source == "self" { | ||
formatedSources = append(formatedSources, "self") | ||
} else { | ||
formatedSources = append(formatedSources, "\""+source+"\"") | ||
} | ||
} | ||
policyHeader = append(policyHeader, fmt.Sprintf("%s=(%s)", name, strings.Join(formatedSources, " "))) | ||
} | ||
} else { | ||
//There are no setting for this field. Assume no permission | ||
policyHeader = append(policyHeader, fmt.Sprintf("%s=()", name)) | ||
} | ||
} | ||
|
||
// Add each policy directive to the header | ||
addDirective("accelerometer", policy.Accelerometer) | ||
addDirective("ambient-light-sensor", policy.AmbientLightSensor) | ||
addDirective("autoplay", policy.Autoplay) | ||
addDirective("battery", policy.Battery) | ||
addDirective("camera", policy.Camera) | ||
addDirective("cross-origin-isolated", policy.CrossOriginIsolated) | ||
addDirective("display-capture", policy.DisplayCapture) | ||
addDirective("document-domain", policy.DocumentDomain) | ||
addDirective("encrypted-media", policy.EncryptedMedia) | ||
addDirective("execution-while-not-rendered", policy.ExecutionWhileNotRendered) | ||
addDirective("execution-while-out-of-viewport", policy.ExecutionWhileOutOfView) | ||
addDirective("fullscreen", policy.Fullscreen) | ||
addDirective("geolocation", policy.Geolocation) | ||
addDirective("gyroscope", policy.Gyroscope) | ||
addDirective("keyboard-map", policy.KeyboardMap) | ||
addDirective("magnetometer", policy.Magnetometer) | ||
addDirective("microphone", policy.Microphone) | ||
addDirective("midi", policy.Midi) | ||
addDirective("navigation-override", policy.NavigationOverride) | ||
addDirective("payment", policy.Payment) | ||
addDirective("picture-in-picture", policy.PictureInPicture) | ||
addDirective("publickey-credentials-get", policy.PublicKeyCredentialsGet) | ||
addDirective("screen-wake-lock", policy.ScreenWakeLock) | ||
addDirective("sync-xhr", policy.SyncXHR) | ||
addDirective("usb", policy.USB) | ||
addDirective("web-share", policy.WebShare) | ||
addDirective("xr-spatial-tracking", policy.XRSpatialTracking) | ||
addDirective("clipboard-read", policy.ClipboardRead) | ||
addDirective("clipboard-write", policy.ClipboardWrite) | ||
addDirective("gamepad", policy.Gamepad) | ||
addDirective("speaker-selection", policy.SpeakerSelection) | ||
addDirective("conversion-measurement", policy.ConversionMeasurement) | ||
addDirective("focus-without-user-activation", policy.FocusWithoutUserActivation) | ||
addDirective("hid", policy.HID) | ||
addDirective("idle-detection", policy.IdleDetection) | ||
addDirective("interest-cohort", policy.InterestCohort) | ||
addDirective("serial", policy.Serial) | ||
addDirective("sync-script", policy.SyncScript) | ||
addDirective("trust-token-redemption", policy.TrustTokenRedemption) | ||
addDirective("unload", policy.Unload) | ||
addDirective("window-placement", policy.WindowPlacement) | ||
addDirective("vertical-scroll", policy.VerticalScroll) | ||
|
||
// Join the directives and set the header | ||
policyHeaderValue := strings.Join(policyHeader, ", ") | ||
|
||
//Inject the new policy into the header | ||
w.Header().Set("Permissions-Policy", policyHeaderValue) | ||
} |
47 changes: 47 additions & 0 deletions
47
src/mod/dynamicproxy/permissionpolicy/permissionpolicy_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package permissionpolicy_test | ||
|
||
import ( | ||
"net/http/httptest" | ||
"strings" | ||
"testing" | ||
|
||
"imuslab.com/zoraxy/mod/dynamicproxy/permissionpolicy" | ||
) | ||
|
||
func TestInjectPermissionPolicyHeader(t *testing.T) { | ||
//Prepare the data for permission policy | ||
testPermissionPolicy := permissionpolicy.GetDefaultPermissionPolicy() | ||
testPermissionPolicy.Geolocation = []string{"self"} | ||
testPermissionPolicy.Microphone = []string{"self", "https://example.com"} | ||
testPermissionPolicy.Camera = []string{"*"} | ||
|
||
tests := []struct { | ||
name string | ||
existingHeader string | ||
policy *permissionpolicy.PermissionsPolicy | ||
expectedHeader string | ||
}{ | ||
{ | ||
name: "Default policy with a few limitations", | ||
existingHeader: "", | ||
policy: testPermissionPolicy, | ||
expectedHeader: `accelerometer=*, ambient-light-sensor=*, autoplay=*, battery=*, camera=*, cross-origin-isolated=*, display-capture=*, document-domain=*, encrypted-media=*, execution-while-not-rendered=*, execution-while-out-of-viewport=*, fullscreen=*, geolocation=(self), gyroscope=*, keyboard-map=*, magnetometer=*, microphone=(self "https://example.com"), midi=*, navigation-override=*, payment=*, picture-in-picture=*, publickey-credentials-get=*, screen-wake-lock=*, sync-xhr=*, usb=*, web-share=*, xr-spatial-tracking=*, clipboard-read=*, clipboard-write=*, gamepad=*, speaker-selection=*, conversion-measurement=*, focus-without-user-activation=*, hid=*, idle-detection=*, interest-cohort=*, serial=*, sync-script=*, trust-token-redemption=*, unload=*, window-placement=*, vertical-scroll=*`, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
rr := httptest.NewRecorder() | ||
if tt.existingHeader != "" { | ||
rr.Header().Set("Permissions-Policy", tt.existingHeader) | ||
} | ||
|
||
permissionpolicy.InjectPermissionPolicyHeader(rr, tt.policy) | ||
|
||
gotHeader := rr.Header().Get("Permissions-Policy") | ||
if !strings.Contains(gotHeader, tt.expectedHeader) { | ||
t.Errorf("got header %s, want %s", gotHeader, tt.expectedHeader) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.