capacitor-sso-webview 0.0.7 → 0.0.8
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.
|
@@ -4,6 +4,9 @@ import android.app.Activity;
|
|
|
4
4
|
import android.app.Dialog;
|
|
5
5
|
import android.graphics.Color;
|
|
6
6
|
import android.net.Uri;
|
|
7
|
+
import android.os.Handler;
|
|
8
|
+
import android.os.Looper;
|
|
9
|
+
import android.util.Log;
|
|
7
10
|
import android.view.Gravity;
|
|
8
11
|
import android.view.ViewGroup;
|
|
9
12
|
import android.webkit.CookieManager;
|
|
@@ -14,8 +17,23 @@ import android.webkit.WebViewClient;
|
|
|
14
17
|
import android.widget.LinearLayout;
|
|
15
18
|
import android.widget.TextView;
|
|
16
19
|
|
|
20
|
+
import java.io.BufferedReader;
|
|
21
|
+
import java.io.IOException;
|
|
22
|
+
import java.io.InputStream;
|
|
23
|
+
import java.io.InputStreamReader;
|
|
24
|
+
import java.net.HttpURLConnection;
|
|
25
|
+
import java.net.URL;
|
|
26
|
+
import java.nio.charset.StandardCharsets;
|
|
27
|
+
import java.util.concurrent.ExecutorService;
|
|
28
|
+
import java.util.concurrent.Executors;
|
|
29
|
+
|
|
17
30
|
public class SSOWebView {
|
|
18
31
|
|
|
32
|
+
private static final String TAG = "SSOWebView";
|
|
33
|
+
|
|
34
|
+
/* Single background thread — cukup untuk satu exchange per login attempt */
|
|
35
|
+
private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
|
|
36
|
+
|
|
19
37
|
public interface Listener {
|
|
20
38
|
void onRedirectIntercepted(String url, String code, String state, String body);
|
|
21
39
|
|
|
@@ -25,7 +43,6 @@ public class SSOWebView {
|
|
|
25
43
|
private Dialog dialog;
|
|
26
44
|
private WebView webView;
|
|
27
45
|
private boolean alreadyRedirected = false;
|
|
28
|
-
private boolean bodyRead = false;
|
|
29
46
|
|
|
30
47
|
public void open(
|
|
31
48
|
final Activity activity,
|
|
@@ -35,7 +52,6 @@ public class SSOWebView {
|
|
|
35
52
|
final String title,
|
|
36
53
|
final Listener listener) {
|
|
37
54
|
alreadyRedirected = false;
|
|
38
|
-
bodyRead = false;
|
|
39
55
|
|
|
40
56
|
dialog = new Dialog(activity, android.R.style.Theme_Light_NoTitleBar_Fullscreen);
|
|
41
57
|
|
|
@@ -105,81 +121,30 @@ public class SSOWebView {
|
|
|
105
121
|
|
|
106
122
|
if (isRedirect && !alreadyRedirected) {
|
|
107
123
|
alreadyRedirected = true;
|
|
108
|
-
/* Biarkan WebView navigate — server akan return JSON body */
|
|
109
|
-
return false;
|
|
110
|
-
}
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
@Override
|
|
115
|
-
public void onPageFinished(WebView view, String pageUrl) {
|
|
116
|
-
super.onPageFinished(view, pageUrl);
|
|
117
|
-
|
|
118
|
-
/* Guard: hanya proses sekali setelah redirect */
|
|
119
|
-
if (bodyRead) return;
|
|
120
|
-
|
|
121
|
-
Uri u = Uri.parse(pageUrl);
|
|
122
|
-
String host = u.getHost();
|
|
123
|
-
String path = u.getPath();
|
|
124
|
-
|
|
125
|
-
boolean isRedirectPage =
|
|
126
|
-
host != null && host.equalsIgnoreCase(redirectHost) &&
|
|
127
|
-
path != null && path.toLowerCase()
|
|
128
|
-
.contains(redirectPathContains.toLowerCase());
|
|
129
124
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
/* Set flag SEGERA — cegah double-fire */
|
|
133
|
-
bodyRead = true;
|
|
134
|
-
|
|
135
|
-
final String finalUrl = pageUrl;
|
|
125
|
+
final String finalUrl = u.toString();
|
|
136
126
|
final String finalCode = u.getQueryParameter("code") != null
|
|
137
127
|
? u.getQueryParameter("code") : "";
|
|
138
128
|
final String finalState = u.getQueryParameter("state") != null
|
|
139
129
|
? u.getQueryParameter("state") : "";
|
|
140
130
|
|
|
141
|
-
/*
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
body = body.replace("\\\"", "\"")
|
|
159
|
-
.replace("\\n", "\n")
|
|
160
|
-
.replace("\\r", "")
|
|
161
|
-
.replace("\\/", "/");
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
final String finalBody = (body != null) ? body : "";
|
|
165
|
-
android.util.Log.d("SSOWebView",
|
|
166
|
-
"body len=" + finalBody.length() +
|
|
167
|
-
" preview=" + finalBody.substring(
|
|
168
|
-
0, Math.min(120, finalBody.length())));
|
|
169
|
-
|
|
170
|
-
activity.runOnUiThread(() -> SSOWebView.this.dismiss());
|
|
171
|
-
|
|
172
|
-
if (listener != null)
|
|
173
|
-
listener.onRedirectIntercepted(
|
|
174
|
-
finalUrl, finalCode, finalState, finalBody);
|
|
175
|
-
}
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
}, 150);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
private void dismiss() {
|
|
182
|
-
SSOWebView.this.dismiss();
|
|
131
|
+
/*
|
|
132
|
+
* PENTING: BATALKAN navigasi (return true), jangan biarkan WebView
|
|
133
|
+
* merender URL ini. Endpoint redirect mengembalikan JSON, bukan
|
|
134
|
+
* HTML — jika WebView mencoba menampilkannya sebagai halaman, hasil
|
|
135
|
+
* yang didapat adalah halaman error native "Webpage not available",
|
|
136
|
+
* bukan body JSON, sehingga JSON.parse di sisi JS selalu gagal.
|
|
137
|
+
*
|
|
138
|
+
* Sebagai gantinya, ambil body via HTTP request native di background
|
|
139
|
+
* thread — pola yang sama seperti fetchJsonFromUrl() pada
|
|
140
|
+
* LoginIdamActivity, yang sudah terbukti bekerja untuk flow login
|
|
141
|
+
* berbasis WebView redirect lainnya di aplikasi ini.
|
|
142
|
+
*/
|
|
143
|
+
dismiss();
|
|
144
|
+
fetchRedirectBody(finalUrl, finalCode, finalState, listener);
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
183
148
|
}
|
|
184
149
|
});
|
|
185
150
|
|
|
@@ -199,6 +164,64 @@ public class SSOWebView {
|
|
|
199
164
|
webView.loadUrl(url);
|
|
200
165
|
}
|
|
201
166
|
|
|
167
|
+
private void fetchRedirectBody(
|
|
168
|
+
final String url,
|
|
169
|
+
final String code,
|
|
170
|
+
final String state,
|
|
171
|
+
final Listener listener) {
|
|
172
|
+
|
|
173
|
+
EXECUTOR.execute(() -> {
|
|
174
|
+
String body;
|
|
175
|
+
HttpURLConnection conn = null;
|
|
176
|
+
try {
|
|
177
|
+
conn = (HttpURLConnection) new URL(url).openConnection();
|
|
178
|
+
conn.setRequestMethod("GET");
|
|
179
|
+
conn.setConnectTimeout(20000);
|
|
180
|
+
conn.setReadTimeout(20000);
|
|
181
|
+
conn.setRequestProperty("Accept", "application/json");
|
|
182
|
+
|
|
183
|
+
int status = conn.getResponseCode();
|
|
184
|
+
InputStream is = (status >= 200 && status < 400)
|
|
185
|
+
? conn.getInputStream() : conn.getErrorStream();
|
|
186
|
+
body = readStream(is);
|
|
187
|
+
|
|
188
|
+
Log.d(TAG, "fetchRedirectBody status=" + status + " len=" + body.length());
|
|
189
|
+
} catch (Exception e) {
|
|
190
|
+
Log.e(TAG, "fetchRedirectBody failed", e);
|
|
191
|
+
/*
|
|
192
|
+
* Bungkus error sebagai JSON agar konsumen JS (yang selalu mem-parse
|
|
193
|
+
* body sebagai JSON dan memeriksa `status`) mendapat pesan yang jelas,
|
|
194
|
+
* alih-alih body kosong atau string mentah yang gagal di-parse.
|
|
195
|
+
*/
|
|
196
|
+
body = "{\"status\":0,\"status_message\":\"" + escapeJson(e.getMessage()) + "\"}";
|
|
197
|
+
} finally {
|
|
198
|
+
if (conn != null) conn.disconnect();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
final String finalBody = body;
|
|
202
|
+
new Handler(Looper.getMainLooper()).post(() -> {
|
|
203
|
+
if (listener != null) {
|
|
204
|
+
listener.onRedirectIntercepted(url, code, state, finalBody);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private static String readStream(InputStream is) throws IOException {
|
|
211
|
+
if (is == null) return "";
|
|
212
|
+
StringBuilder sb = new StringBuilder();
|
|
213
|
+
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
|
214
|
+
String line;
|
|
215
|
+
while ((line = br.readLine()) != null) sb.append(line);
|
|
216
|
+
}
|
|
217
|
+
return sb.toString();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private static String escapeJson(String s) {
|
|
221
|
+
if (s == null) return "Unknown network error";
|
|
222
|
+
return s.replace("\\", "\\\\").replace("\"", "\\\"");
|
|
223
|
+
}
|
|
224
|
+
|
|
202
225
|
public void dismiss() {
|
|
203
226
|
try {
|
|
204
227
|
if (webView != null) {
|