1. 소개
이 절은 비규범적입니다.
이 명세는 스크립트가 제한된 API를 호출하는 기능을 신뢰하는 다른 탐색 컨텍스트에 위임할 수 있는 메커니즘을 정의합니다. 여기서는 위임된 기능을 대상 탐색 컨텍스트에 제한된 시간 동안 제공하는 동적 위임 메커니즘에 초점을 맞춥니다.
1.1. 기능 위임이란?
웹의 많은 기능은 JS에서 제한된 방식으로 사용할 수 있습니다. 예를 들면 다음과 같습니다.
-
대부분의 브라우저는 사용자가 최근 페이지와 상호작용했거나 해당 페이지의 출처에서 팝업을 열도록 허용한 경우에만
Window.open()을 통한 팝업을 허용합니다. -
샌드박스가 적용된 iframe은 특정 샌드박스 속성이나 프레임 안에서의 사용자 상호작용 없이는
requestFullscreen()를 통해 자신을 전체 화면으로 만들 수 없습니다.
기능 위임이란 프레임이 제한된 API를 호출하는 기능을 동적으로 포기하고 신뢰할 수 있는 다른 (하위) 프레임으로 이전할 수 있게 하는 것입니다. 여기서 “동적”이란 위임의 효과가 위임되는
기능에서 정한 제한된 시간 동안만 지속된다는 뜻입니다. 이는 탐색 컨텍스트에 iframe의
allow
속성으로 기능을 정적으로(로드 시점에) 노출하는 것과 다릅니다. 정적 노출에서는 하위 프레임에 기능을 시간 제한 없이 제공합니다.
1.2. 위임 시작과 기능 사용
기능 위임이 효과를 가지려면 서로 다른 두 단계가 필요합니다. 첫 단계는 “시작”으로, 한 탐색 컨텍스트가 다른 탐색 컨텍스트에 특정 기능이 위임됨을 알립니다. 시작 후 두 번째(즉, 수신 측) 탐색 컨텍스트가 위임된 기능을 “사용”합니다. 보통은 해당 기능에서 정의한 메서드를 호출한다는 뜻입니다. 이 기능 위임 명세는 두 번째 단계에서 쓰는 API 인터페이스를 정의하지 않지만 API의 내부 동작을 다시 정의합니다.
따라서 이 명세는 시작 단계의 API를 정의하는 부분과 이를 “사용하는” 특정 API의 위임 동작을 정의하는 부분으로 나뉩니다. 두 번째 부분은 결제 요청 API에 필요한 동작 변경에 초점을 맞추며, 앞으로 기능 위임을 이용하는 다른 API에 비슷한 변경을 적용할 때 지침이 됩니다.
1.3. 일시적인 사용 가능성
위의 두 단계는 모두 본질적으로 시간 제한이 있습니다.
-
시작 단계는 활성화를 소비하므로 최근 사용자 활성화가 발생한 경우에만 허용됩니다. 또한 여기서 사용자 활성화를 소비하면 사용자 활성화 한 번당 위임 메커니즘을 한 번만 사용할 수 있습니다. 이를 통해 여러 프레임에 반복해서 위임을 시도하여 위임된 API의 사용자 활성화 제한을 사실상 우회하는 등의 악용을 방지합니다.
-
시작 단계가 성공적으로 완료되면 위임된 API는 대상 탐색 컨텍스트에서 몇 초 동안만 사용할 수 있습니다. 정확한 제한 시간은 해당 API의 명세가 위임 동작을 정의하는 방식에 따라 달라집니다. 자체 제한 시간을 정의하지 않은 API의 기본 제한 시간은 사용자 활성화의 만료 시간과 같습니다.
2. 예제
show()
— 하위 프레임에 메시지를
전송하면서 위임할 기능을 지정하는 옵션을 추가합니다:
window. onclick= () => { targetWindow. postMessage( 'a_message' , { delegate: "payment" }); };
메시지를 받으면 하위 프레임은 사용자 활성화를 받지 않았더라도 show()를
사용할 수 있습니다:
window. onmessage= () => { const payRequest= new PaymentRequest(...); const payResponse= await payRequest. show(); ... }
3. 기능 위임 시작
한 탐색 컨텍스트가 다른 탐색 컨텍스트에 기능을 위임하려면 두 번째 탐색 컨텍스트에 메시지를 보내면서 기능을 지정하는 추가 WindowPostMessageOptions인
delegate를 붙입니다. 이 옵션의 값은 반드시 기능 식별자여야 합니다. 값이 사용자 에이전트가 지원하는 기능 중 어느
것에도 해당하지 않으면 반드시 이 옵션을 무시해야 합니다.
3.1. HTML 명세에 대한 임시 수정
WindowPostMessageOptions의
IDL 정의에 다음 필드를 추가합니다:
DOMString? delegate;
창 메시지 전송 알고리즘에서 다음 단계:
transfer를 options["transfer"]로 둡니다.
뒤에 다음 두 단계를 추가합니다:
-
delegate를 options["delegate"]로 둡니다.
-
delegate가 null이 아니면:
-
사용자 에이전트가 delegate로 표시된 기능의 위임을 지원하지 않으면 "NotSupportedError" DOMException을 던집니다.
-
targetWindow의 연결된 Document에 사용이 허용되지 않은 기능을 delegate가 가리키면 "NotAllowedError" DOMException을 던집니다.
-
targetOrigin가 단일 U+002A 별표 문자(*)이면 "NotAllowedError" DOMException을 던집니다.
옵션 targetOrigin의 기본값은 "/"이며 메시지를 동일 출처 대상으로 제한합니다. "*" 이외의 문자열을 사용해야 한다는 추가 요건은 교차 출처 메시지에서 의도한 수신 대상의 구체적인 출처를 지정해야 함을 뜻합니다. -
source를 incumbentSettings의 전역 객체로 둡니다.
-
source에 일시적 활성화가 없으면 "NotAllowedError" DOMException을 던집니다.
-
사용자 활성화를 소비합니다. 대상은 source입니다.
-
4. 위임된 기능 추적
탐색 컨텍스트에 위임된 기능은 Window.DELEGATED_CAPABILITY_TIMESTAMPS라는 맵으로 추적합니다. 기능이 Window에
위임될 때마다 DELEGATED_CAPABILITY_TIMESTAMPS에 항목을 추가합니다. 키는 그 기능을
나타내는 기능 식별자이고 값은 현재
DOMHighResTimeStamp입니다.
맵에 같은 키의 항목이 이미 있으면 기존 값을 현재 DOMHighResTimeStamp로
갱신합니다.
4.1. HTML 명세에 대한 임시 수정
창 메시지 전송 알고리즘 바로 앞에 다음 문단을 삽입합니다:
탐색 컨텍스트에 위임된 기능을 추적하기 위해 각
Window에는 맵이 있습니다. 이름은 DELEGATED_CAPABILITY_TIMESTAMPS이며 기능 식별자를DOMHighResTimeStamp에 대응시킵니다. 이 맵은 빈 맵으로 초기화됩니다.
창 메시지 전송 알고리즘의 현재 8단계에 두 하위 단계를 추가합니다. 첫 번째 추가 하위 단계는 다음 하위 단계 뒤에 삽입합니다:
전역 작업을 큐에 넣습니다...
origin을 incumbentSettings의 출처를 직렬화한 결과로 둡니다.
다음과 같습니다:
-
전역 작업을 큐에 넣습니다... (변경 없음)
-
delegate를 options["delegate"]로 둡니다.
-
두 번째 추가 하위 단계는 다음 하위 단계 뒤에 삽입합니다:
전역 작업을 큐에 넣습니다...
newPorts를 ...로 구성된 새 동결 배열로 둡니다.
다음과 같습니다:
-
전역 작업을 큐에 넣습니다... (변경 없음)
-
newPorts를 ...로 구성된 새 동결 배열로 둡니다. (번호 외에는 변경 없음)
-
delegate가 null이 아니고 사용자 에이전트가 delegate의 위임을 지원하면 DELEGATED_CAPABILITY_TIMESTAMPS[delegate]를 현재 고해상도 시간으로 설정합니다.
-
5. 위임된 기능의 동작 정의
위임 동작을 정의하는 기능은 그 기능에 적합한 방식으로 Window.DELEGATED_CAPABILITY_TIMESTAMPS의 해당 항목을 사용합니다. 아래는 특정
기능에 필요한 명세 변경입니다.
5.1. 결제 요청 명세에 대한 임시 수정
show()
알고리즘에서 위임 동작을 구현하도록 다음 단계들을 교체합니다:
다음 두 단계:
request의 관련 전역 객체에 일시적 활성화가 없으면:
"SecurityError" DOMException으로 거부된 promise를 반환합니다.
관련 전역 객체의 사용자 활성화를 소비합니다.
를 다음 세 단계로 교체합니다:
-
request의 관련 전역 객체에 일시적 활성화가 없고 그 관련 전역 객체의 타임스탬프 DELEGATED_CAPABILITY_TIMESTAMPS["payment"]가 undefined이거나 만료되었으면:
-
"SecurityError" DOMException으로 거부된 promise를 반환합니다.
-
-
request의 관련 전역 객체에 일시적 활성화가 없으면 맵 항목 DELEGATED_CAPABILITY_TIMESTAMPS["payment"]를 지웁니다.
-
그렇지 않으면 사용자 활성화를 소비합니다. 대상은 관련 전역 객체입니다.
5.2. 전체 화면 명세에 대한 임시 수정
requestFullscreen()
알고리즘에서 위임 동작을 구현하도록 다음과 같이 변경합니다:
5단계의 마지막 조건:
다음 조건 중 하나라도 false이면 error를 true로 설정합니다: ...
this의 관련 전역 객체에 일시적 활성화가 있거나 사용자가 일으킨 방향 변경으로 알고리즘이 실행됩니다.
를 다음으로 교체합니다:
-
다음 조건 중 하나라도 false이면 error를 true로 설정합니다: ... (변경 없음)
-
this의 관련 전역 객체에 일시적 활성화가 있거나, 해당 객체의 타임스탬프 DELEGATED_CAPABILITY_TIMESTAMPS["fullscreen"]가 undefined가 아니고 만료되지 않았거나, 사용자가 일으킨 방향 변경으로 알고리즘이 실행됩니다.
-
다음 10단계 바로 앞에:
fullscreenElements를 처음에는 this만 포함하는 순서 있는 집합으로 둡니다.
다음 새 단계를 삽입합니다:
-
this의 관련 전역 객체에 일시적 활성화가 없으면 해당 객체의 맵 항목 DELEGATED_CAPABILITY_TIMESTAMPS["fullscreen"]를 지웁니다.
-
fullscreenElements를 처음에는 this만 포함하는 순서 있는 집합으로 둡니다. (번호 외에는 변경 없음)
5.3. 임시 수정: [SCREEN-CAPTURE] 명세
getDisplayMedia()
알고리즘에서 위임 동작을 구현하도록 다음과 같이 변경합니다:
3단계의 조건:
this의 관련 전역 객체에 일시적 활성화가 없으면 name 속성값이 InvalidStateError인 DOMException 객체로 거부된 promise를 반환합니다.
를 다음으로 교체합니다:
-
this의 관련 전역 객체에 일시적 활성화가 없고, 타임스탬프 DELEGATED_CAPABILITY_TIMESTAMPS["display-capture"]가 this의 관련 전역 객체에서 undefined이거나 만료되었으면 거부된 promise를 반환합니다. 거부 사유는 DOMException 객체이며 그
name속성값은InvalidStateError입니다.