From dab956fe851f6c2aa20f87e079dbe1662135b85e Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 20 Jul 2023 08:05:38 +0800 Subject: [PATCH 1/6] common oidc Signed-off-by: dignow --- flutter/assets/auth-apple.svg | 1 + flutter/assets/auth-azure.svg | 1 + flutter/assets/auth-default.svg | 14 +++++ flutter/assets/auth-facebook.svg | 1 + .../assets/{GitHub.svg => auth-github.svg} | 0 .../assets/{Google.svg => auth-google.svg} | 0 flutter/assets/{Okta.svg => auth-okta.svg} | 0 flutter/lib/common.dart | 7 +++ flutter/lib/common/widgets/login.dart | 51 +++++++++---------- flutter/lib/models/user_model.dart | 6 +-- 10 files changed, 51 insertions(+), 30 deletions(-) create mode 100644 flutter/assets/auth-apple.svg create mode 100644 flutter/assets/auth-azure.svg create mode 100644 flutter/assets/auth-default.svg create mode 100644 flutter/assets/auth-facebook.svg rename flutter/assets/{GitHub.svg => auth-github.svg} (100%) rename flutter/assets/{Google.svg => auth-google.svg} (100%) rename flutter/assets/{Okta.svg => auth-okta.svg} (100%) diff --git a/flutter/assets/auth-apple.svg b/flutter/assets/auth-apple.svg new file mode 100644 index 000000000..a3c2e871d --- /dev/null +++ b/flutter/assets/auth-apple.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flutter/assets/auth-azure.svg b/flutter/assets/auth-azure.svg new file mode 100644 index 000000000..0482b22e6 --- /dev/null +++ b/flutter/assets/auth-azure.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flutter/assets/auth-default.svg b/flutter/assets/auth-default.svg new file mode 100644 index 000000000..905c9ca9b --- /dev/null +++ b/flutter/assets/auth-default.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/flutter/assets/auth-facebook.svg b/flutter/assets/auth-facebook.svg new file mode 100644 index 000000000..d921a6716 --- /dev/null +++ b/flutter/assets/auth-facebook.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flutter/assets/GitHub.svg b/flutter/assets/auth-github.svg similarity index 100% rename from flutter/assets/GitHub.svg rename to flutter/assets/auth-github.svg diff --git a/flutter/assets/Google.svg b/flutter/assets/auth-google.svg similarity index 100% rename from flutter/assets/Google.svg rename to flutter/assets/auth-google.svg diff --git a/flutter/assets/Okta.svg b/flutter/assets/auth-okta.svg similarity index 100% rename from flutter/assets/Okta.svg rename to flutter/assets/auth-okta.svg diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index e96f02772..71fbfcdd9 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -2314,3 +2314,10 @@ Widget unreadTopRightBuilder(RxInt? count, {Widget? icon}) { ], ); } + +String toCapitalized(String s) { + if (s.isEmpty) { + return s; + } + return s.substring(0, 1).toUpperCase() + s.substring(1); +} diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index 17cc7090c..1eecdc2d5 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -13,13 +13,13 @@ import '../../common.dart'; import './dialog.dart'; class _IconOP extends StatelessWidget { - final String icon; - final double iconWidth; + final String op; + final String? icon; final EdgeInsets margin; const _IconOP( {Key? key, + required this.op, required this.icon, - required this.iconWidth, this.margin = const EdgeInsets.symmetric(horizontal: 4.0)}) : super(key: key); @@ -27,10 +27,15 @@ class _IconOP extends StatelessWidget { Widget build(BuildContext context) { return Container( margin: margin, - child: SvgPicture.asset( - 'assets/$icon.svg', - width: iconWidth, - ), + child: icon == null + ? SvgPicture.asset( + 'assets/auth-${op.toLowerCase()}.svg', + width: 20, + ) + : SvgPicture.string( + icon!, + width: 20, + ), ); } } @@ -38,7 +43,7 @@ class _IconOP extends StatelessWidget { class ButtonOP extends StatelessWidget { final String op; final RxString curOP; - final double iconWidth; + final String? icon; final Color primaryColor; final double height; final Function() onTap; @@ -47,7 +52,7 @@ class ButtonOP extends StatelessWidget { Key? key, required this.op, required this.curOP, - required this.iconWidth, + required this.icon, required this.primaryColor, required this.height, required this.onTap, @@ -71,15 +76,15 @@ class ButtonOP extends StatelessWidget { SizedBox( width: 30, child: _IconOP( - icon: op, - iconWidth: iconWidth, + op: op, + icon: icon, margin: EdgeInsets.only(right: 5), )), Expanded( child: FittedBox( fit: BoxFit.scaleDown, child: Center( - child: Text('${translate("Continue with")} $op')))), + child: Text('${translate("Continue with")} ${toCapitalized(op)}')))), ], ))), ), @@ -89,8 +94,8 @@ class ButtonOP extends StatelessWidget { class ConfigOP { final String op; - final double iconWidth; - ConfigOP({required this.op, required this.iconWidth}); + final String? icon; + ConfigOP({required this.op, required this.icon}); } class WidgetOP extends StatefulWidget { @@ -182,7 +187,7 @@ class _WidgetOPState extends State { ButtonOP( op: widget.config.op, curOP: widget.curOP, - iconWidth: widget.config.iconWidth, + icon: widget.config.icon, primaryColor: str2color(widget.config.op, 0x7f), height: 36, onTap: () async { @@ -380,7 +385,7 @@ Future loginDialog() async { final loginOptions = [].obs; Future.delayed(Duration.zero, () async { - loginOptions.value = await UserModel.queryLoginOptions(); + loginOptions.value = await UserModel.queryOidcLoginOptions(); }); final res = await gFFI.dialogManager.show((setState, close, context) { @@ -460,12 +465,8 @@ Future loginDialog() async { } thirdAuthWidget() => Obx(() { - final oidcOptions = loginOptions - .where((opt) => opt.startsWith(kAuthReqTypeOidc)) - .map((opt) => opt.substring(kAuthReqTypeOidc.length)) - .toList(); return Offstage( - offstage: oidcOptions.isEmpty, + offstage: loginOptions.isEmpty, child: Column( children: [ const SizedBox( @@ -480,12 +481,8 @@ Future loginDialog() async { height: 8.0, ), LoginWidgetOP( - ops: [ - ConfigOP(op: 'GitHub', iconWidth: 20), - ConfigOP(op: 'Google', iconWidth: 20), - ConfigOP(op: 'Okta', iconWidth: 38), - ] - .where((op) => oidcOptions.contains(op.op.toLowerCase())) + ops: loginOptions + .map((e) => ConfigOP(op: e['name'], icon: e['icon'])) .toList(), curOP: curOP, cbLogin: (Map authBody) { diff --git a/flutter/lib/models/user_model.dart b/flutter/lib/models/user_model.dart index 83df2e632..18f409608 100644 --- a/flutter/lib/models/user_model.dart +++ b/flutter/lib/models/user_model.dart @@ -163,15 +163,15 @@ class UserModel { return loginResponse; } - static Future> queryLoginOptions() async { + static Future> queryOidcLoginOptions() async { try { final url = await bind.mainGetApiServer(); if (url.trim().isEmpty) return []; - final resp = await http.get(Uri.parse('$url/api/login-options')); + final resp = await http.get(Uri.parse('$url/api/oidc/login-options')); return jsonDecode(resp.body); } catch (e) { debugPrint( - "queryLoginOptions: jsonDecode resp body failed: ${e.toString()}"); + "queryOidcLoginOptions: jsonDecode resp body failed: ${e.toString()}"); return []; } } From 3f3c45b6633631aef6d6f3231ffdbe79736e1bc8 Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 20 Jul 2023 08:27:30 +0800 Subject: [PATCH 2/6] common oidc, tmp commit Signed-off-by: dignow --- flutter/lib/common/widgets/login.dart | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index 1eecdc2d5..12171be34 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -66,7 +66,7 @@ class ButtonOP extends StatelessWidget { width: 200, child: Obx(() => ElevatedButton( style: ElevatedButton.styleFrom( - primary: curOP.value.isEmpty || curOP.value == op + backgroundColor: curOP.value.isEmpty || curOP.value == op ? primaryColor : Colors.grey, ).copyWith(elevation: ButtonStyleButton.allOrNull(0.0)), @@ -74,17 +74,21 @@ class ButtonOP extends StatelessWidget { child: Row( children: [ SizedBox( - width: 30, - child: _IconOP( - op: op, - icon: icon, - margin: EdgeInsets.only(right: 5), - )), + width: 30, + child: _IconOP( + op: op, + icon: icon, + margin: EdgeInsets.only(right: 5), + ), + ), Expanded( - child: FittedBox( - fit: BoxFit.scaleDown, - child: Center( - child: Text('${translate("Continue with")} ${toCapitalized(op)}')))), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Center( + child: Text( + '${translate("Continue with")} ${op.toLowerCase() == "github" ? "GitHub" : toCapitalized(op)}')), + ), + ), ], ))), ), From 0bf007e63c6a137a918c152ec4a4f14b9a6d4e73 Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 20 Jul 2023 11:09:08 +0800 Subject: [PATCH 3/6] common oidc, debug Signed-off-by: dignow --- flutter/lib/common/widgets/login.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index 12171be34..11cb067ac 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -12,6 +12,8 @@ import 'package:url_launcher/url_launcher.dart'; import '../../common.dart'; import './dialog.dart'; +const kOpSvgList = ['github', 'google', 'apple', 'okta', 'facebook', 'azure']; + class _IconOP extends StatelessWidget { final String op; final String? icon; @@ -25,11 +27,12 @@ class _IconOP extends StatelessWidget { @override Widget build(BuildContext context) { + final svgFile = kOpSvgList.contains(op.toLowerCase()) ? op.toLowerCase() : 'default'; return Container( margin: margin, child: icon == null ? SvgPicture.asset( - 'assets/auth-${op.toLowerCase()}.svg', + 'assets/auth-$svgFile.svg', width: 20, ) : SvgPicture.string( From 35c1cee18bbaba30ada3bd2c2663f49e9d0b1510 Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 20 Jul 2023 22:58:57 +0800 Subject: [PATCH 4/6] common oidc, add auth0 Signed-off-by: dignow --- flutter/assets/auth-auth0.svg | 1 + flutter/lib/common/widgets/login.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 flutter/assets/auth-auth0.svg diff --git a/flutter/assets/auth-auth0.svg b/flutter/assets/auth-auth0.svg new file mode 100644 index 000000000..e8c7557e7 --- /dev/null +++ b/flutter/assets/auth-auth0.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flutter/lib/common/widgets/login.dart b/flutter/lib/common/widgets/login.dart index 11cb067ac..d7037e58f 100644 --- a/flutter/lib/common/widgets/login.dart +++ b/flutter/lib/common/widgets/login.dart @@ -12,7 +12,7 @@ import 'package:url_launcher/url_launcher.dart'; import '../../common.dart'; import './dialog.dart'; -const kOpSvgList = ['github', 'google', 'apple', 'okta', 'facebook', 'azure']; +const kOpSvgList = ['github', 'google', 'apple', 'okta', 'facebook', 'azure', 'auth0']; class _IconOP extends StatelessWidget { final String op; From 4e1d7ca3de8f9ff22d79712d5a3543416deb6923 Mon Sep 17 00:00:00 2001 From: dignow Date: Thu, 20 Jul 2023 23:23:59 +0800 Subject: [PATCH 5/6] update svg Signed-off-by: dignow --- flutter/assets/auth-github.svg | 2 +- flutter/assets/auth-google.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/flutter/assets/auth-github.svg b/flutter/assets/auth-github.svg index ef0bb12a7..1ba71c98b 100644 --- a/flutter/assets/auth-github.svg +++ b/flutter/assets/auth-github.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/flutter/assets/auth-google.svg b/flutter/assets/auth-google.svg index df394a84f..f9ab170e6 100644 --- a/flutter/assets/auth-google.svg +++ b/flutter/assets/auth-google.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 2c86fac20824e6cca1f98bfd71a1d22ac2b13e93 Mon Sep 17 00:00:00 2001 From: dignow Date: Mon, 7 Aug 2023 19:08:29 +0800 Subject: [PATCH 6/6] refact, common oidc Signed-off-by: dignow --- flutter/lib/models/user_model.dart | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/flutter/lib/models/user_model.dart b/flutter/lib/models/user_model.dart index 18f409608..ebed47587 100644 --- a/flutter/lib/models/user_model.dart +++ b/flutter/lib/models/user_model.dart @@ -167,8 +167,20 @@ class UserModel { try { final url = await bind.mainGetApiServer(); if (url.trim().isEmpty) return []; - final resp = await http.get(Uri.parse('$url/api/oidc/login-options')); - return jsonDecode(resp.body); + final resp = await http.get(Uri.parse('$url/api/login-options')); + final List ops = []; + for (final item in jsonDecode(resp.body)) { + ops.add(item as String); + } + for (final item in ops) { + if (item.startsWith('common-oidc/')) { + return jsonDecode(item.substring('common-oidc/'.length)); + } + } + return ops + .where((item) => item.startsWith('oidc/')) + .map((item) => {'name': item.substring('oidc/'.length)}) + .toList(); } catch (e) { debugPrint( "queryOidcLoginOptions: jsonDecode resp body failed: ${e.toString()}");