기능 위임

커뮤니티 그룹 보고서 초안,

이 버전:
https://wicg.github.io/capability-delegation/spec.html
이슈 추적:
GitHub
편집자:
(Google Canada)

요약

제한된 API를 사용할 수 있는 기능을 다른 창으로 이전합니다.

이 문서의 상태

이 명세는 웹 플랫폼 인큐베이터 커뮤니티 그룹이 발행했습니다. W3C 표준이 아니며 W3C 표준화 과정에 있지도 않습니다. W3C 커뮤니티 기여자 라이선스 계약(CLA)에는 제한적인 옵트아웃이 있으며 다른 조건도 적용됩니다. W3C 커뮤니티 그룹과 비즈니스 그룹에 관해 더 알아보세요.

1. 소개

이 절은 비규범적입니다.

이 명세는 스크립트가 제한된 API를 호출하는 기능을 신뢰하는 다른 탐색 컨텍스트에 위임할 수 있는 메커니즘을 정의합니다. 여기서는 위임된 기능을 대상 탐색 컨텍스트에 제한된 시간 동안 제공하는 동적 위임 메커니즘에 초점을 맞춥니다.

1.1. 기능 위임이란?

웹의 많은 기능은 JS에서 제한된 방식으로 사용할 수 있습니다. 예를 들면 다음과 같습니다.

기능 위임이란 프레임이 제한된 API를 호출하는 기능을 동적으로 포기하고 신뢰할 수 있는 다른 (하위) 프레임으로 이전할 수 있게 하는 것입니다. 여기서 “동적”이란 위임의 효과가 위임되는 기능에서 정한 제한된 시간 동안만 지속된다는 뜻입니다. 이는 탐색 컨텍스트에 iframe의 allow 속성으로 기능을 정적으로(로드 시점에) 노출하는 것과 다릅니다. 정적 노출에서는 하위 프레임에 기능을 시간 제한 없이 제공합니다.

1.2. 위임 시작과 기능 사용

기능 위임이 효과를 가지려면 서로 다른 두 단계가 필요합니다. 첫 단계는 “시작”으로, 한 탐색 컨텍스트가 다른 탐색 컨텍스트에 특정 기능이 위임됨을 알립니다. 시작 후 두 번째(즉, 수신 측) 탐색 컨텍스트가 위임된 기능을 “사용”합니다. 보통은 해당 기능에서 정의한 메서드를 호출한다는 뜻입니다. 이 기능 위임 명세는 두 번째 단계에서 쓰는 API 인터페이스를 정의하지 않지만 API의 내부 동작을 다시 정의합니다.

따라서 이 명세는 시작 단계의 API를 정의하는 부분과 이를 “사용하는” 특정 API의 위임 동작을 정의하는 부분으로 나뉩니다. 두 번째 부분은 결제 요청 API에 필요한 동작 변경에 초점을 맞추며, 앞으로 기능 위임을 이용하는 다른 API에 비슷한 변경을 적용할 때 지침이 됩니다.

1.3. 일시적인 사용 가능성

위의 두 단계는 모두 본질적으로 시간 제한이 있습니다.

  1. 시작 단계는 활성화를 소비하므로 최근 사용자 활성화가 발생한 경우에만 허용됩니다. 또한 여기서 사용자 활성화를 소비하면 사용자 활성화 한 번당 위임 메커니즘을 한 번만 사용할 수 있습니다. 이를 통해 여러 프레임에 반복해서 위임을 시도하여 위임된 API의 사용자 활성화 제한을 사실상 우회하는 등의 악용을 방지합니다.

  2. 시작 단계가 성공적으로 완료되면 위임된 API는 대상 탐색 컨텍스트에서 몇 초 동안만 사용할 수 있습니다. 정확한 제한 시간은 해당 API의 명세가 위임 동작을 정의하는 방식에 따라 달라집니다. 자체 제한 시간을 정의하지 않은 API의 기본 제한 시간은 사용자 활성화의 만료 시간과 같습니다.

2. 예제

사이트가 마우스 클릭 후 하위 프레임에 다음 API를 호출할 기능을 위임하려면: [payment-request] 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;

창 메시지 전송 알고리즘에서 다음 단계:

  1. transfer를 options["transfer"]로 둡니다.

뒤에 다음 두 단계를 추가합니다:

  1. delegate를 options["delegate"]로 둡니다.

  2. delegate가 null이 아니면:

    1. 사용자 에이전트가 delegate로 표시된 기능의 위임을 지원하지 않으면 "NotSupportedError" DOMException을 던집니다.

    2. targetWindow의 연결된 Document에 사용이 허용되지 않은 기능을 delegate가 가리키면 "NotAllowedError" DOMException을 던집니다.

    3. targetOrigin가 단일 U+002A 별표 문자(*)이면 "NotAllowedError" DOMException을 던집니다.

      옵션 targetOrigin의 기본값은 "/"이며 메시지를 동일 출처 대상으로 제한합니다. "*" 이외의 문자열을 사용해야 한다는 추가 요건은 교차 출처 메시지에서 의도한 수신 대상의 구체적인 출처를 지정해야 함을 뜻합니다.
    4. source를 incumbentSettings의 전역 객체로 둡니다.

    5. source에 일시적 활성화가 없으면 "NotAllowedError" DOMException을 던집니다.

    6. 사용자 활성화를 소비합니다. 대상은 source입니다.

4. 위임된 기능 추적

탐색 컨텍스트에 위임된 기능은 Window.DELEGATED_CAPABILITY_TIMESTAMPS라는 맵으로 추적합니다. 기능이 Window에 위임될 때마다 DELEGATED_CAPABILITY_TIMESTAMPS에 항목을 추가합니다. 키는 그 기능을 나타내는 기능 식별자이고 값은 현재 DOMHighResTimeStamp입니다. 맵에 같은 키의 항목이 이미 있으면 기존 값을 현재 DOMHighResTimeStamp로 갱신합니다.

4.1. HTML 명세에 대한 임시 수정

창 메시지 전송 알고리즘 바로 앞에 다음 문단을 삽입합니다:

탐색 컨텍스트에 위임된 기능을 추적하기 위해 각 Window에는 맵이 있습니다. 이름은 DELEGATED_CAPABILITY_TIMESTAMPS이며 기능 식별자를 DOMHighResTimeStamp에 대응시킵니다. 이 맵은 빈 맵으로 초기화됩니다.

창 메시지 전송 알고리즘의 현재 8단계에 두 하위 단계를 추가합니다. 첫 번째 추가 하위 단계는 다음 하위 단계 뒤에 삽입합니다:

  1. 전역 작업을 큐에 넣습니다...

    1. origin을 incumbentSettings의 출처를 직렬화한 결과로 둡니다.

다음과 같습니다:

  1. 전역 작업을 큐에 넣습니다... (변경 없음)

    1. delegate를 options["delegate"]로 둡니다.

두 번째 추가 하위 단계는 다음 하위 단계 뒤에 삽입합니다:

  1. 전역 작업을 큐에 넣습니다...

    1. newPorts를 ...로 구성된 새 동결 배열로 둡니다.

다음과 같습니다:

  1. 전역 작업을 큐에 넣습니다... (변경 없음)

    1. newPorts를 ...로 구성된 새 동결 배열로 둡니다. (번호 외에는 변경 없음)

    2. delegate가 null이 아니고 사용자 에이전트가 delegate의 위임을 지원하면 DELEGATED_CAPABILITY_TIMESTAMPS[delegate]를 현재 고해상도 시간으로 설정합니다.

5. 위임된 기능의 동작 정의

위임 동작을 정의하는 기능은 그 기능에 적합한 방식으로 Window.DELEGATED_CAPABILITY_TIMESTAMPS의 해당 항목을 사용합니다. 아래는 특정 기능에 필요한 명세 변경입니다.

5.1. 결제 요청 명세에 대한 임시 수정

show() 알고리즘에서 위임 동작을 구현하도록 다음 단계들을 교체합니다:

다음 두 단계:

  1. request의 관련 전역 객체에 일시적 활성화가 없으면:

    1. "SecurityError" DOMException으로 거부된 promise를 반환합니다.

  2. 관련 전역 객체의 사용자 활성화를 소비합니다.

를 다음 세 단계로 교체합니다:

  1. request의 관련 전역 객체에 일시적 활성화가 없고 그 관련 전역 객체의 타임스탬프 DELEGATED_CAPABILITY_TIMESTAMPS["payment"]가 undefined이거나 만료되었으면:

    1. "SecurityError" DOMException으로 거부된 promise를 반환합니다.

  2. request의 관련 전역 객체에 일시적 활성화가 없으면 맵 항목 DELEGATED_CAPABILITY_TIMESTAMPS["payment"]를 지웁니다.

  3. 그렇지 않으면 사용자 활성화를 소비합니다. 대상은 관련 전역 객체입니다.

5.2. 전체 화면 명세에 대한 임시 수정

requestFullscreen() 알고리즘에서 위임 동작을 구현하도록 다음과 같이 변경합니다:

5단계의 마지막 조건:

  1. 다음 조건 중 하나라도 false이면 error를 true로 설정합니다: ...

    • this의 관련 전역 객체에 일시적 활성화가 있거나 사용자가 일으킨 방향 변경으로 알고리즘이 실행됩니다.

를 다음으로 교체합니다:

  1. 다음 조건 중 하나라도 false이면 error를 true로 설정합니다: ... (변경 없음)

    • this의 관련 전역 객체에 일시적 활성화가 있거나, 해당 객체의 타임스탬프 DELEGATED_CAPABILITY_TIMESTAMPS["fullscreen"]가 undefined가 아니고 만료되지 않았거나, 사용자가 일으킨 방향 변경으로 알고리즘이 실행됩니다.

다음 10단계 바로 앞에:

  1. fullscreenElements를 처음에는 this만 포함하는 순서 있는 집합으로 둡니다.

다음 새 단계를 삽입합니다:

  1. this의 관련 전역 객체에 일시적 활성화가 없으면 해당 객체의 맵 항목 DELEGATED_CAPABILITY_TIMESTAMPS["fullscreen"]를 지웁니다.

  2. fullscreenElements를 처음에는 this만 포함하는 순서 있는 집합으로 둡니다. (번호 외에는 변경 없음)

5.3. 임시 수정: [SCREEN-CAPTURE] 명세

getDisplayMedia() 알고리즘에서 위임 동작을 구현하도록 다음과 같이 변경합니다:

3단계의 조건:

  1. this의 관련 전역 객체에 일시적 활성화가 없으면 name 속성값이 InvalidStateError인 DOMException 객체로 거부된 promise를 반환합니다.

를 다음으로 교체합니다:

  1. this의 관련 전역 객체에 일시적 활성화가 없고, 타임스탬프 DELEGATED_CAPABILITY_TIMESTAMPS["display-capture"]가 this의 관련 전역 객체에서 undefined이거나 만료되었으면 거부된 promise를 반환합니다. 거부 사유는 DOMException 객체이며 그 name 속성값은 InvalidStateError입니다.

적합성

문서 규칙

적합성 요건은 서술적 진술과 RFC 2119 용어를 함께 사용하여 표현합니다. 이 문서의 규범적 부분에서 “반드시 해야 함(MUST)”, “해서는 안 됨(MUST NOT)”, “필수(REQUIRED)”, “반드시 해야 함(SHALL)”, “해서는 안 됨(SHALL NOT)”, “하는 것이 좋음(SHOULD)”, “하지 않는 것이 좋음(SHOULD NOT)”, “권장(RECOMMENDED)”, “해도 됨(MAY)”, “선택 사항(OPTIONAL)”이라는 핵심어는 RFC 2119의 설명에 따라 해석합니다. 다만 가독성을 위해 이 명세에서는 이러한 단어를 모두 대문자로 표기하지 않습니다.

이 명세의 모든 본문은 비규범적이라고 명시된 절, 예제, 참고를 제외하고 규범적입니다. [RFC2119]

이 명세의 예제는 “예를 들어”로 시작하거나 다음처럼 class="example"를 사용하여 규범적 본문과 구분합니다:

이것은 비규범적 예제의 한 예입니다.

비규범적 참고는 “참고”로 시작하며 다음처럼 class="note"를 사용하여 규범적 본문과 구분합니다:

참고: 이것은 비규범적 참고입니다.

적합한 알고리즘

알고리즘의 일부로 명령형으로 표현된 요건(예: “앞에 있는 공백 문자를 모두 제거한다” 또는 “false를 반환하고 이 단계들을 중단한다”)은 해당 알고리즘을 소개할 때 사용한 핵심어(“반드시 해야 함”, “하는 것이 좋음”, “해도 됨” 등)의 의미로 해석합니다.

알고리즘이나 구체적인 단계로 표현된 적합성 요건은 최종 결과가 동등하다면 어떤 방식으로든 구현할 수 있습니다. 특히 이 명세의 알고리즘은 성능보다는 이해하기 쉽게 만드는 데 목적이 있습니다. 구현자는 최적화하는 것이 권장됩니다.

색인

이 명세에서 정의한 용어

참조 문서에서 정의한 용어

참고 문헌

규범적 참고 문헌

[FULLSCREEN]
Philip Jägenstedt. 전체 화면 API 표준. 현행 표준. URL: https://fullscreen.spec.whatwg.org/
[HR-TIME-3]
Yoav Weiss. 고해상도 시간. URL: https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren 외. HTML 표준. 현행 표준. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 표준. 현행 표준. URL: https://infra.spec.whatwg.org/
[PAYMENT-REQUEST-1.1]
Marcos Caceres; Rouslan Solomakhin; Ian Jacobs. 결제 요청 API 1.1. URL: https://w3c.github.io/payment-request/
[PERMISSIONS-POLICY-1]
Ian Clelland. 권한 정책. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. RFC에서 요구 수준을 나타내는 핵심어. 1997년 3월. 현행 최선 관행. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SCREEN-CAPTURE]
Jan-Ivar Bruaroey; Elad Alon. 화면 캡처. URL: https://w3c.github.io/mediacapture-screen-share/
[WebCryptoAPI]
Mark Watson. 웹 암호화 API. URL: https://w3c.github.io/webcrypto/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 표준. 현행 표준. URL: https://webidl.spec.whatwg.org/

비규범적 참고 문헌

[PAYMENT-REQUEST]
Marcos Caceres; Rouslan Solomakhin; Ian Jacobs. 결제 요청 API. URL: https://w3c.github.io/payment-request/