C.W.K.
Stream
Lesson 04 of 05 · published

activeTab 와 다른 narrow permission — 무서운 경고 회피

~11 min · activeTab, permissions, narrow-permissions, ux

Level 0Extension 입덕
0 XP0/54 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"Chrome 의 most-installed extension 의 절반이 all-websites 경고 절대 안 받음 — activeTab 과 같은 문제 푸는 narrow permission 한 줌 사용하니까. Lesson 4 가 단축 list — <all_urls> 대신 손 뻗을 거."

activeTab — 일꾼

"activeTab" 이 user 가 이런 거 통해 extension 부르는 순간 시작하는 현재-active tab 의 임시 host access 부여하는 특별 API permission:

  • Toolbar icon click (chrome.action.onClicked 나 popup open).
  • 키보드 command (chrome.commands.onCommand).
  • Context menu (chrome.contextMenus.onClicked).

Grant 가 cover: 그 tab 의 chrome.scripting.executeScript, 그 tab 의 chrome.tabs.captureVisibleTab, tab.url / tab.title read. User 가 tab 을 새 URL 로 navigate 하거나 tab 닫을 때까지 지속.

결정적: install 경고 없음. activeTab 자체가 prompt 에 아무것도 추가 안 함. User-gesture trigger 패턴과 결합 시 all-sites alarm 없이 "on demand 동작, 요청할 때만" semantics 얻음.

activeTab vs Programmatic Injection

혼란 포인트: activeTab 이 host access 부여; scripting 이 API 부여. 보통 둘 다 원함:

"permissions": ["activeTab", "scripting"]

그 둘 선언하면 SW 가 gesture handler 안에서 user-active tab 의 chrome.scripting.executeScript 호출 가능. host_permissions 필요 없음. 항상-on injection 도 원하지 안 한 한 content-script 선언 필요 없음.

알 가치 있는 다른 narrow permission

  • tabGroups — Chrome 의 tab grouping read / 수정. 자체 install 경고 없음.
  • notificationschrome.notifications.create 통해 데스크톱 notification 표시. Mild install 경고 ("Show notifications"); 대부분 user 한테 무해.
  • alarms — one-shot 이나 recurring SW wake-up 스케줄. Install 경고 없음. setInterval/setTimeout (SW 와 함께 죽음) 대체.
  • identity — Google sign-in 의 OAuth flow. Install 경고가 host access 가 아닌 나중 요청할 scope 요약.
  • webNavigation — 세밀한 navigation event. "Read your browsing history" 경고 동반; tabs 가 덜 무섭게 대부분 같은 ground cover.
  • contextMenus — 이미 manifest 에. 경고 없음.
  • storage, commands, sidePanel, omnibox, action — 다 silent.

조심해서 다룰 permission

이것들 각자 자체 시끄러운 경고 추가. 정말 필요할 때만 사용, optional_permissions 뒤 gating 고려:

  • history — "Read and modify your browsing history." 드물게 필요; tabs + per-tab cache 가 보통 use case cover.
  • cookies — "Read and modify cookies on all sites." Clip-saving extension 엔 거의 필요 없음.
  • geolocation — "Detect your physical location." User 놀라게 함; runtime 에 요청.
  • nativeMessaging — "Communicate with cooperating native applications." 데스크톱 binary 와 대화 가능; 공격 surface 열음.
  • debugger — "Use the developer tools on any tab." Power-user only; install 경고 시끄럽고 정당.
  • webRequest — "Block or modify network requests." MV3 가 MV2 대비 이거 무겁게 제한; 좁은 사용도 경고 발생.

대체 게임

Host permission 이나 무서운 API permission 선언 전 물어 봐: "더 narrow 한 방법 있어?" 보통 있음:

  • 주기적 background job 필요? setInterval + persistent worker 아닌 alarms.
  • Per-site 선호 기억 필요? cookies 아닌 storage.
  • 현재 page read 필요? host_permissions 아닌 activeTab + scripting.
  • User 가 방금 방문한 site 알기 필요? historywebNavigation 아닌 onUpdated 가진 tabs.
  • User 가 타이핑할 때 동작 필요? 단축키엔 commands, 주소창 keyword 엔 omnibox. debugger 안 됨.
activeTab + scripting + storage 가 실제 extension 의 큰 fraction cover 하는 no-warning trinity. Narrow permission 먼저 손 뻗기; 더 narrow 한 경로 없을 때만 host_permissions 선언.
activeTab 이 content_scripts.matches 와 상호작용하는 법. activeTab 이 선언된 content script 를 auto-inject 안 함 — 그냥 chrome.scripting 과 tab.url access 해금. activeTab 부를 때 content script load 원하면, gesture handler 에서 chrome.scripting.executeScript 호출 필수. Static content_scripts manifest entry 가 매칭 URL 에 항상-on 이고 activeTab 과 따로 content_scripts.matches 가 govern.

Code

background.js — activeTab 이 user-click tab 의 scripting 해금·javascript
// background.js — gesture handler 안 activeTab + scripting
chrome.action.onClicked.addListener(async (tab) => {
  if (!tab.id) return;
  // activeTab + scripting 이 host_permissions 없이도 이거 허용
  const [result] = await chrome.scripting.executeScript({
    target: { tabId: tab.id },
    func: () => ({ url: location.href, title: document.title }),
  });
  console.log("[ClipDeck SW] page info:", result.result);
});
background.js — 주기적 SW work 위해 chrome.alarms 가 setInterval 대체·javascript
// background.js — SW 살려 두지 안 고 주기적 work 위한 alarms
chrome.runtime.onInstalled.addListener(() => {
  chrome.alarms.create("clipdeck-cleanup", {
    when: Date.now() + 60_000, // 1 분 후 첫 실행
    periodInMinutes: 60, // 그 다음 매 시간
  });
});

chrome.alarms.onAlarm.addListener(async (alarm) => {
  if (alarm.name !== "clipdeck-cleanup") return;
  // pausedTabs (Track 5) 에서 stale tab id 정리
  const { pausedTabs = [] } = await chrome.storage.local.get("pausedTabs");
  const tabs = await chrome.tabs.query({});
  const live = new Set(tabs.map((t) => t.id));
  const trimmed = pausedTabs.filter((id) => live.has(id));
  if (trimmed.length !== pausedTabs.length) {
    await chrome.storage.local.set({ pausedTabs: trimmed });
  }
});
manifest.json — narrow-permission ClipDeck shape·json
{
  "permissions": [
    "storage",
    "activeTab",
    "scripting",
    "sidePanel",
    "contextMenus",
    "commands",
    "alarms",
    "tabs"
  ],
  "host_permissions": [],
  "optional_permissions": ["downloads", "notifications"],
  "optional_host_permissions": ["https://*/*", "http://*/*"]
}

External links

Exercise

clipdeck/manifest.json 을 세 번째 code block 으로 update — "alarms" 를 permissions 에 추가, host_permissions 비워 두기, 넓은 URL access 를 optional_host_permissions 로 옮기기. Reload. chrome://extensions → ClipDeck → Details 에서 install 경고가 이제 'Read your browsing history' (tabs 에서) 와 'Read and change your data on sites you visit' (content_scripts.matches 가 여전히 라서) 로 보임 — Lesson 3 에서 content_scripts.matches 좁혔으면 'all websites' 보다 narrow, 아니면 여전히 시끄러움. 두 번째 code block (alarms cleanup) 을 background.js 에 추가. Clip 몇 개 저장, 그 tab 중 일부를 un-pause 안 하고 닫기, 한 시간 기다리기 (또는 테스트 위해 alarm timing 을 periodInMinutes: 1 로 변경). pausedTabs cleanup 이 돌고 죽은 tab id 정리. 전후 DevTools 에서 chrome.storage 확인.
Hint
Host_permissions drop 후에도 install 경고 변함없으면 content_scripts.matches: [''] 가 여전히 work — 좁히든가 (Lesson 3) activeTab + programmatic injection 으로 전환 (이 lesson). chrome.alarms.onAlarm 이 fire 안 하면, alarm 이 아마 생성 안 됨 chrome.runtime.onInstalled 가 아직 안 돌아서 — extension 제거하고 unpacked 디렉토리 다시 load 시도, fresh onInstalled trigger. MV3 의 chrome.alarms minimum period 가 30 초; 그 아래 값은 silent round-up.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.