mirror of
https://github.com/DefinedNet/mobile_nebula.git
synced 2025-01-19 03:37:02 +00:00
64d45f66c7
This updates flutter to 3.24.1, the latest stable version, and also updates our flutter dependencies to latest. It targets the latest android sdk, 34, which is required if we want to publish a new version to the Google Play store. I also needed to make a few adjustments to handle deprecations. The biggest change is that I needed to wrap the main widget in MaterialApp to avoid problems with AdaptiveSwitch in iOS.
210 lines
7.1 KiB
Dart
210 lines
7.1 KiB
Dart
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
|
import 'package:mobile_nebula/components/FormPage.dart';
|
|
import 'package:mobile_nebula/components/config/ConfigItem.dart';
|
|
import 'package:mobile_nebula/components/config/ConfigSection.dart';
|
|
import 'package:mobile_nebula/models/Certificate.dart';
|
|
import 'package:mobile_nebula/screens/siteConfig/AddCertificateScreen.dart';
|
|
import 'package:mobile_nebula/services/utils.dart';
|
|
|
|
/// Displays the details of a CertificateInfo object. Respects incomplete objects (missing validity or rawCert)
|
|
class CertificateDetailsScreen extends StatefulWidget {
|
|
const CertificateDetailsScreen({
|
|
Key? key,
|
|
required this.certInfo,
|
|
this.onDelete,
|
|
this.onSave,
|
|
this.onReplace,
|
|
this.pubKey,
|
|
this.privKey,
|
|
required this.supportsQRScanning,
|
|
}) : super(key: key);
|
|
|
|
final CertificateInfo certInfo;
|
|
|
|
// onDelete is used to remove a CA cert
|
|
final Function? onDelete;
|
|
|
|
// onSave is used to install a new certificate
|
|
final Function? onSave;
|
|
|
|
// onReplace is used to install a new certificate over top of the old one
|
|
final ValueChanged<CertificateResult>? onReplace;
|
|
|
|
// pubKey and privKey should be set if onReplace is not null.
|
|
final String? pubKey;
|
|
final String? privKey;
|
|
|
|
final bool supportsQRScanning;
|
|
|
|
@override
|
|
_CertificateDetailsScreenState createState() => _CertificateDetailsScreenState();
|
|
}
|
|
|
|
class _CertificateDetailsScreenState extends State<CertificateDetailsScreen> {
|
|
bool changed = false;
|
|
CertificateResult? certResult;
|
|
late CertificateInfo certInfo;
|
|
ScrollController controller = ScrollController();
|
|
|
|
@override
|
|
void initState() {
|
|
certInfo = widget.certInfo;
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FormPage(
|
|
title: 'Certificate Details',
|
|
scrollController: controller,
|
|
changed: widget.onSave != null || changed,
|
|
onSave: () {
|
|
if (widget.onSave != null) {
|
|
Navigator.pop(context);
|
|
widget.onSave!();
|
|
} else if (widget.onReplace != null) {
|
|
Navigator.pop(context);
|
|
widget.onReplace!(certResult!);
|
|
}
|
|
},
|
|
hideSave: widget.onSave == null && widget.onReplace == null,
|
|
child: Column(children: [
|
|
_buildID(),
|
|
_buildFilters(),
|
|
_buildValid(),
|
|
_buildAdvanced(),
|
|
_buildReplace(),
|
|
_buildDelete(),
|
|
]),
|
|
);
|
|
}
|
|
|
|
Widget _buildID() {
|
|
return ConfigSection(children: <Widget>[
|
|
ConfigItem(label: Text('Name'), content: SelectableText(certInfo.cert.details.name)),
|
|
ConfigItem(
|
|
label: Text('Type'), content: Text(certInfo.cert.details.isCa ? 'CA certificate' : 'Client certificate')),
|
|
]);
|
|
}
|
|
|
|
Widget _buildValid() {
|
|
var valid = Text('yes');
|
|
if (certInfo.validity != null && !certInfo.validity!.valid) {
|
|
valid = Text(certInfo.validity!.valid ? 'yes' : certInfo.validity!.reason,
|
|
style: TextStyle(color: CupertinoColors.systemRed.resolveFrom(context)));
|
|
}
|
|
return ConfigSection(
|
|
label: 'VALIDITY',
|
|
children: <Widget>[
|
|
ConfigItem(label: Text('Valid?'), content: valid),
|
|
ConfigItem(
|
|
label: Text('Created'), content: SelectableText(certInfo.cert.details.notBefore.toLocal().toString())),
|
|
ConfigItem(
|
|
label: Text('Expires'), content: SelectableText(certInfo.cert.details.notAfter.toLocal().toString())),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildFilters() {
|
|
List<Widget> items = [];
|
|
if (certInfo.cert.details.groups.length > 0) {
|
|
items.add(ConfigItem(label: Text('Groups'), content: SelectableText(certInfo.cert.details.groups.join(', '))));
|
|
}
|
|
|
|
if (certInfo.cert.details.ips.length > 0) {
|
|
items.add(ConfigItem(label: Text('IPs'), content: SelectableText(certInfo.cert.details.ips.join(', '))));
|
|
}
|
|
|
|
if (certInfo.cert.details.subnets.length > 0) {
|
|
items.add(ConfigItem(label: Text('Subnets'), content: SelectableText(certInfo.cert.details.subnets.join(', '))));
|
|
}
|
|
|
|
return items.length > 0
|
|
? ConfigSection(label: certInfo.cert.details.isCa ? 'FILTERS' : 'DETAILS', children: items)
|
|
: Container();
|
|
}
|
|
|
|
Widget _buildAdvanced() {
|
|
return ConfigSection(
|
|
children: <Widget>[
|
|
ConfigItem(
|
|
label: Text('Fingerprint'),
|
|
content:
|
|
SelectableText(certInfo.cert.fingerprint, style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14)),
|
|
crossAxisAlignment: CrossAxisAlignment.start),
|
|
ConfigItem(
|
|
label: Text('Public Key'),
|
|
content: SelectableText(certInfo.cert.details.publicKey,
|
|
style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14)),
|
|
crossAxisAlignment: CrossAxisAlignment.start),
|
|
certInfo.rawCert != null
|
|
? ConfigItem(
|
|
label: Text('PEM Format'),
|
|
content: SelectableText(certInfo.rawCert!, style: TextStyle(fontFamily: 'RobotoMono', fontSize: 14)),
|
|
crossAxisAlignment: CrossAxisAlignment.start)
|
|
: Container(),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildReplace() {
|
|
if (widget.onReplace == null || widget.pubKey == null || widget.privKey == null) {
|
|
return Container();
|
|
}
|
|
|
|
return Padding(
|
|
padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10),
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
child: PlatformElevatedButton(
|
|
child: Text('Replace certificate'),
|
|
color: CupertinoColors.systemRed.resolveFrom(context),
|
|
onPressed: () {
|
|
Utils.openPage(context, (context) {
|
|
return AddCertificateScreen(
|
|
onReplace: (result) {
|
|
setState(() {
|
|
changed = true;
|
|
certResult = result;
|
|
certInfo = result.certInfo;
|
|
});
|
|
// Slam the page back to the top
|
|
controller.animateTo(0,
|
|
duration: const Duration(milliseconds: 10), curve: Curves.linearToEaseOut);
|
|
},
|
|
pubKey: widget.pubKey!,
|
|
privKey: widget.privKey!,
|
|
supportsQRScanning: widget.supportsQRScanning,
|
|
);
|
|
});
|
|
})));
|
|
}
|
|
|
|
Widget _buildDelete() {
|
|
if (widget.onDelete == null) {
|
|
return Container();
|
|
}
|
|
|
|
var title = certInfo.cert.details.isCa ? 'Delete CA?' : 'Delete cert?';
|
|
|
|
return Padding(
|
|
padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10),
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
child: PlatformElevatedButton(
|
|
child: Text('Delete'),
|
|
color: CupertinoColors.systemRed.resolveFrom(context),
|
|
onPressed: () => Utils.confirmDelete(context, title, () async {
|
|
Navigator.pop(context);
|
|
widget.onDelete!();
|
|
}))));
|
|
}
|
|
}
|