Skip to content

Commit

Permalink
Merge branch 'next'
Browse files Browse the repository at this point in the history
  • Loading branch information
rk0cc committed Jul 29, 2024
2 parents a819b13 + 85ab72d commit d60825a
Show file tree
Hide file tree
Showing 31 changed files with 860 additions and 305 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode/
13 changes: 13 additions & 0 deletions superuser/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## 2.0.0

* Add user's joined group in local machine scope.

## 2.0.0-m.1

* `isSuperuser` can returns true without superuser permission activated.
* Windows: Uses `NetUserGetLocalGroups` to find current user is a member of `Administrators`.
* UNIX: Determine user joined default `sudo` command enabled groups (`admin` in macOS, `sudo` in Linux).
* Expand UNIX's error code to unsigned 32-bits length with two 16-bits segmentes:
* Lower 16-bits reuses origin error numbers from libraries.
* Upper 16-bits denotes error categories that causing error thrown.

## 1.0.2

* Add assertion to prevent using mock interface in release mode.
Expand Down
2 changes: 2 additions & 0 deletions superuser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ void main() {

Demo application of `superuser` has been available in [release page](https://github.com/rk0cc/superuser/releases) in Windows and Linux application.

These demo animations are for reference only, conditions and contents may be differ without notice.

### Open without superuser right

![Open demo application oridinary](https://github.com/user-attachments/assets/5b973019-c6d6-4466-9f60-01c86b06c1c8)
Expand Down
40 changes: 39 additions & 1 deletion superuser/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,38 @@ class Context extends StatelessWidget {

@override
Widget build(BuildContext context) {
void onDisplayingGroups() async {
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (context) {
List<String> gpList = Superuser.groups.toList(growable: false);

return AlertDialog(
title: const Text("Groups"),
content:
Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Text("Total joined groups: ${gpList.length}"),
SizedBox(
width: 400,
height: 275,
child: ListView.builder(
shrinkWrap: true,
itemCount: gpList.length,
itemBuilder: (context, index) =>
ListTile(title: Text(gpList[index]))))
]),
actions: <TextButton>[
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text("OK"))
],
);
});
}

return Scaffold(
appBar: AppBar(title: const Text("Superuser")),
drawer: Drawer(
Expand Down Expand Up @@ -121,7 +153,13 @@ class Context extends StatelessWidget {
child: ListTile(
title: const Text("Run as superuser", style: _titleStyle),
trailing: Text(Superuser.isActivated ? "Yes" : "No",
style: _valueStyle)))
style: _valueStyle))),
const Divider(),
ListTile(
title: const Text("Group"),
trailing: ElevatedButton(
onPressed: onDisplayingGroups,
child: const Text("List all joined groups")))
]));
}
}
24 changes: 11 additions & 13 deletions superuser/example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -211,31 +211,29 @@ packages:
path: ".."
relative: true
source: path
version: "1.0.1"
version: "2.0.0"
superuser_interfaces:
dependency: transitive
description:
name: superuser_interfaces
sha256: e7725726dfe90c535e8907149e255cc0647dc9dd7b08bb4286727e16c1915a35
sha256: "483e04fc06f00035a94c77d35db6d44afe4b5022171c50bf58db3e267495a0b3"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.1.0"
superuser_plugin_unix:
dependency: transitive
description:
name: superuser_plugin_unix
sha256: d0786e1fe844e22594108f12dd2ab8f99b84618376b421122b5a2c2853c34f13
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path: "../../superuser_plugin_unix"
relative: true
source: path
version: "2.0.0"
superuser_plugin_windows:
dependency: transitive
description:
name: superuser_plugin_windows
sha256: "7531992b26f70cb0f3d1c76ba7e45c76968aa447039c6444e64deafce5e04e3f"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
path: "../../superuser_plugin_windows"
relative: true
source: path
version: "2.0.0"
term_glyph:
dependency: transitive
description:
Expand Down
4 changes: 2 additions & 2 deletions superuser/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: superuser_demo
description: "Flutter superuser package demo application"
publish_to: 'none'
version: 1.0.0
version: 2.0.0
environment:
sdk: '>=3.4.0 <4.0.0'
dependencies:
Expand All @@ -15,6 +15,6 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^4.0.0
flutter_lints: ^4.0.0
flutter:
uses-material-design: true
12 changes: 6 additions & 6 deletions superuser/lib/src/instance.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:superuser_plugin_unix/superuser_plugin_unix.dart';
import 'package:superuser_plugin_windows/superuser_plugin_windows.dart';

import 'exception.dart';
import 'utils.dart';

SuperuserInterface? _instance;

Expand Down Expand Up @@ -45,17 +46,16 @@ abstract final class SuperuserInstance {
/// the provided interface should not be closed. Otherwise,
/// it throws [ArgumentError].
///
/// In [kReleaseMode] or non widget testing process, [suInterface] will not
/// accept [MockSuperuser] and throw [IllegalInstanceError] instead. Therefore,
/// ensure all dummy data are removed already.
/// [suInterface] can only accept [MockSuperuser] if [kDebugMode]
/// or it performs widget testing. Using mock interface in
/// [kReleaseMode] or [kProfileMode] causes [IllegalInstanceError]
/// throw.
static void bindInstance(SuperuserInterface? suInterface) {
if (!Platform.isWindows && !Platform.isMacOS && !Platform.isLinux) {
throw UnsupportedError("Unknown platform");
}

if (kReleaseMode &&
!Platform.environment.containsKey("FLUTTER_TEST") &&
suInterface is MockSuperuser) {
if (!kUnderDevelop && suInterface is MockSuperuser) {
throw IllegalInstanceError(
"Mock instance cannot be used in release mode.");
}
Expand Down
8 changes: 8 additions & 0 deletions superuser/lib/src/utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:meta/meta.dart';

@internal
bool get kUnderDevelop =>
kDebugMode || Platform.environment.containsKey("FLUTTER_TEST");
26 changes: 20 additions & 6 deletions superuser/lib/superuser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,33 @@ abstract final class Superuser {
const Superuser._();

/// Determine this program is executed by a user, who is superuser exactly or
/// one of members in superuser group.
/// one of members in superuser group that it is possible to toggle [isActivated]
/// (it can be executed with restricted permission that making [isActivated] retains
/// false).
///
/// For UNIX platform, it returns true if user who execute this program is `root`
/// or a member of built-in group that can uses `sudo` command. (`admin` for macOS
/// or `sudo` for majority of Linux systems).
///
/// In Windows, it returns true if current user is a member of `Administrators`
/// group in local machine. This detection does not consider Active Directory
/// users.
static bool get isSuperuser => instance.isSuperuser;

/// Determine this program is running with superuser role.
/// Determine this program is running with superuser role that it can
/// access and modify protected location programmatically.
///
/// If this getter called in UNIX platforms (macOS or Linux),
/// it is an alias getter of [isSuperuser] since `root` is one and only
/// user can be represented as superuser.
/// UNIX platforms (macOS and Linux) only consider executor is `root`,
/// whatever how this program called.
///
/// For Windows platform, it consider this process has been elevated
/// or not.
/// or not, which should be positive if and only if user granted UAC
/// prompt.
static bool get isActivated => instance.isActivated;

/// Obtain username who call current program.
static String get whoAmI => instance.whoAmI;

/// Obtain user's associated groups in local system.
static Iterable<String> get groups => instance.groups;
}
8 changes: 4 additions & 4 deletions superuser/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: superuser
description: Detect, verify user who execute Flutter program has superuser role and running with superuser permission.
version: 1.0.2
version: 2.0.0
homepage: https://github.com/rk0cc/superuser
repository: https://github.com/rk0cc/superuser/tree/main/superuser
funding:
Expand All @@ -18,9 +18,9 @@ dependencies:
flutter:
sdk: flutter
meta: ^1.12.0
superuser_interfaces: ^2.0.0
superuser_plugin_unix: ^1.0.0
superuser_plugin_windows: ^1.0.0
superuser_interfaces: ^2.1.0
superuser_plugin_unix: ^2.0.0
superuser_plugin_windows: ^2.0.0
dev_dependencies:
flutter_lints: ^4.0.0
platforms:
Expand Down
4 changes: 4 additions & 0 deletions superuser_interfaces/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.1.0

* Add user groups getter.

## 2.0.0

* Mark `SuperuserInterface` final
Expand Down
36 changes: 36 additions & 0 deletions superuser_interfaces/lib/src/exceptions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import 'dart:io';

/// Indicate any errors encountered when fetching properties
/// in [SuperuserInterface].
class SuperuserProcessError extends Error implements OSError {
/// Error code returned from native library.
@override
final int errorCode;

/// Message to explain [errorCode].
@override
final String message;

/// Create [SuperuserProcessError] with given [errorCode].
///
/// Optionally, provide a [message] for further explaination
/// of error.
SuperuserProcessError(this.errorCode, [this.message = ""]);

@override
String toString() {
StringBuffer buf = StringBuffer();

buf.write("SuperuserProcessError: ");

if (message.isNotEmpty) {
buf
..write(message)
..write(" (error code: $errorCode)");
} else {
buf.write("process return with error code $errorCode");
}

return buf.toString();
}
}
Loading

0 comments on commit d60825a

Please sign in to comment.