mp 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/lib/mp/frame_unblocker.rb +5 -2
- data/lib/mp/server.rb +32 -8
- data/lib/mp/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e0e1a8144762d89c2522e81fbb0b6e979802ea3989730337d45e49c31cbe6c2f
|
|
4
|
+
data.tar.gz: 86aced39b324abbbc2b7dcdb20d42b7dd8ede154055bfaec651997d93ba08f7b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c9907e65113fe1743a3f09bee33ad883d3b01dafc792fa6b78971549d5a1323e75062f1e6c0ef59c9b4d767e5ebd63ece2859745c54fdb0a4e4449c86c48554e
|
|
7
|
+
data.tar.gz: 51943720c9294c0af440068ade78de35a1b95468b6fbcc944dbe3a1fa1d01c9933cec15228a8cd6892900561e0b4c2e7c0c54e3376f62c2a645c57f12d5c56ad
|
data/README.md
CHANGED
|
@@ -59,7 +59,7 @@ https://example.com
|
|
|
59
59
|
```
|
|
60
60
|
````
|
|
61
61
|
|
|
62
|
-
本文には `http(s)` の URL か、デッキからの相対パス(`./page.html`)を書きます。`X-Frame-Options` などで埋め込みを拒否するサイトも表示できます。
|
|
62
|
+
本文には `http(s)` の URL か、デッキからの相対パス(`./page.html`)を書きます。`X-Frame-Options` などで埋め込みを拒否するサイトも表示できます。JavaScript、WebAssembly、Web Worker を使うページも動きます。ディレクトリを指すときは `./app/` のように末尾に `/` を付けると `index.html` を開きます。
|
|
63
63
|
|
|
64
64
|
| 属性 | 説明 |
|
|
65
65
|
| --- | --- |
|
|
@@ -181,7 +181,7 @@ Ruby のローカルサーバ(puma)がスライドを配信し、Chrome をア
|
|
|
181
181
|
- サーバは `127.0.0.1` のみで待ち受け、全パスにランダムトークンを要求する
|
|
182
182
|
- WebSocket は Origin を検証する
|
|
183
183
|
- CSP により、デッキ内の HTML に書いたスクリプトは実行されない
|
|
184
|
-
-
|
|
184
|
+
- 埋め込むローカルページは別 origin(`localhost`)で配信し、ターミナルへ接続できない
|
|
185
185
|
- コマンドは Enter を押すまで実行されない
|
|
186
186
|
|
|
187
187
|
それでも、Enter を押せば書かれたコマンドは実行されます。**他人が作ったデッキは内容を確認してから発表してください。**
|
|
@@ -190,6 +190,7 @@ Ruby のローカルサーバ(puma)がスライドを配信し、Chrome をア
|
|
|
190
190
|
|
|
191
191
|
## 制限
|
|
192
192
|
|
|
193
|
+
- `SharedArrayBuffer` が必要なページ(Cross-Origin Isolation が前提のもの)は動きません
|
|
193
194
|
- 埋め込みページは iframe なので、サードパーティ Cookie の制限によりログイン状態を維持できないサイトがあります
|
|
194
195
|
- `:smile:` 形式の絵文字ショートコードは未対応です(Unicode の絵文字は使えます)
|
|
195
196
|
- 発表者ビューから入力できるのは `Enter` だけです。台本にないコマンドを打つときは、聴衆画面のターミナルをクリックしてください
|
|
@@ -200,9 +201,10 @@ Ruby のローカルサーバ(puma)がスライドを配信し、Chrome をア
|
|
|
200
201
|
bundle exec rake test
|
|
201
202
|
bundle exec ruby test/e2e.rb
|
|
202
203
|
bundle exec ruby test/presenter_e2e.rb
|
|
204
|
+
bundle exec ruby test/embed_e2e.rb
|
|
203
205
|
```
|
|
204
206
|
|
|
205
|
-
`test
|
|
207
|
+
`test/*_e2e.rb` と `test/e2e.rb` はヘッドレス Chrome で実際に動かして確認します。Web 埋め込みの確認にはネットワーク接続が必要です。
|
|
206
208
|
|
|
207
209
|
`vendor/assets` には xterm.js と KaTeX を同梱しています。実行に Node.js は不要です。
|
|
208
210
|
|
data/lib/mp/frame_unblocker.rb
CHANGED
|
@@ -45,10 +45,13 @@ module Mp
|
|
|
45
45
|
private
|
|
46
46
|
|
|
47
47
|
# サイトをまたぐ iframe は別プロセスの子ターゲットになるので、そちらにも同じ設定をする
|
|
48
|
+
# Worker なども一時停止した状態で届く。Fetch を持たないので iframe だけを設定し、
|
|
49
|
+
# どのターゲットも必ず再開する(再開しないと Worker が止まったままになる)
|
|
48
50
|
def prepare_child(params)
|
|
49
51
|
session = params["sessionId"]
|
|
50
|
-
watch(session)
|
|
51
|
-
|
|
52
|
+
watch(session) if params.dig("targetInfo", "type") == "iframe"
|
|
53
|
+
ensure
|
|
54
|
+
@cdp.cast("Runtime.runIfWaitingForDebugger", {}, session_id: session)
|
|
52
55
|
end
|
|
53
56
|
|
|
54
57
|
def watch(session)
|
data/lib/mp/server.rb
CHANGED
|
@@ -18,6 +18,7 @@ module Mp
|
|
|
18
18
|
# ランダムトークンを要求し、WebSocket は Origin も検証する。
|
|
19
19
|
class Server
|
|
20
20
|
HOST = "127.0.0.1"
|
|
21
|
+
CONTENT_HOST = "localhost"
|
|
21
22
|
PUBLIC_DIR = File.expand_path("../../public", __dir__)
|
|
22
23
|
VENDOR_DIR = File.expand_path("../../vendor/assets", __dir__)
|
|
23
24
|
THEME_DIR = File.expand_path("../../themes", __dir__)
|
|
@@ -51,6 +52,10 @@ module Mp
|
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
def origin = "http://#{HOST}:#{@port}"
|
|
55
|
+
|
|
56
|
+
# 埋め込むローカルページの配信元。アプリと別 origin にして、ページの JS が
|
|
57
|
+
# ターミナルの WebSocket やデッキの API へ触れないようにする
|
|
58
|
+
def content_origin = "http://#{CONTENT_HOST}:#{@port}"
|
|
54
59
|
def boot_url = "#{origin}/#{@token}/_mp/boot"
|
|
55
60
|
def app_url = "#{origin}/#{@token}/"
|
|
56
61
|
def presenter_url = "#{origin}/#{@token}/presenter"
|
|
@@ -78,7 +83,10 @@ module Mp
|
|
|
78
83
|
prefix = "/#{@token}/"
|
|
79
84
|
return not_found unless path.start_with?(prefix)
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
relative = path.delete_prefix(prefix)
|
|
87
|
+
return embedded_page(relative) if env["HTTP_HOST"] == "#{CONTENT_HOST}:#{@port}"
|
|
88
|
+
|
|
89
|
+
route(relative, env)
|
|
82
90
|
end
|
|
83
91
|
|
|
84
92
|
private
|
|
@@ -108,7 +116,15 @@ module Mp
|
|
|
108
116
|
end
|
|
109
117
|
|
|
110
118
|
def deck_json
|
|
111
|
-
@deck.to_h
|
|
119
|
+
deck = @deck.to_h
|
|
120
|
+
embeds = deck[:embeds].transform_values { |embed| embed[:type] == "web" ? embed.merge(src: embed_url(embed[:src])) : embed }
|
|
121
|
+
deck.merge(embeds: embeds, themeCss: theme_css)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def embed_url(src)
|
|
125
|
+
return src if src.empty? || src.match?(%r{\Ahttps?://}i)
|
|
126
|
+
|
|
127
|
+
"#{content_origin}/#{@token}/#{src.sub(%r{\A(\./|/)+}, "")}"
|
|
112
128
|
end
|
|
113
129
|
|
|
114
130
|
def theme_css
|
|
@@ -136,18 +152,26 @@ module Mp
|
|
|
136
152
|
|
|
137
153
|
# デッキのあるディレクトリのファイル(画像など)
|
|
138
154
|
def deck_file(relative)
|
|
155
|
+
full = resolve_deck_path(relative)
|
|
156
|
+
full ? file(full, sandbox_headers(full)) : not_found
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# 別 origin で配信するので sandbox は不要。wasm や ES モジュールを普通に読み込める
|
|
160
|
+
def embedded_page(relative)
|
|
161
|
+
full = resolve_deck_path(relative.empty? || relative.end_with?("/") ? "#{relative}index.html" : relative)
|
|
162
|
+
full ? file(full) : not_found
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def resolve_deck_path(relative)
|
|
139
166
|
relative = Rack::Utils.unescape_path(relative)
|
|
140
|
-
return
|
|
167
|
+
return if relative.split("/").any? { _1.start_with?(".") }
|
|
141
168
|
|
|
142
169
|
base = File.realpath(@deck.base_dir)
|
|
143
170
|
full = File.expand_path(relative, base)
|
|
144
|
-
|
|
145
|
-
return not_found unless inside?(base, File.realpath(full))
|
|
146
|
-
|
|
147
|
-
file(full, sandbox_headers(full))
|
|
171
|
+
full if File.file?(full) && inside?(base, File.realpath(full))
|
|
148
172
|
end
|
|
149
173
|
|
|
150
|
-
#
|
|
174
|
+
# アプリの origin で HTML が動くと PTY の WebSocket へ届くので、origin を持たせない
|
|
151
175
|
def sandbox_headers(path)
|
|
152
176
|
return {} unless SANDBOXED_TYPES.include?(mime(path))
|
|
153
177
|
|
data/lib/mp/version.rb
CHANGED