Compare commits
4 Commits
d96e039cc0
...
e0d9f223dc
Author | SHA1 | Date |
---|---|---|
Jeff | e0d9f223dc | |
Jeff | 956826a77b | |
Jeff | 082b07eee8 | |
Jeff | 34482a673d |
|
@ -0,0 +1,55 @@
|
|||
BasedOnStyle: Google
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveAssignments: 'false'
|
||||
AlignConsecutiveDeclarations: 'false'
|
||||
AlignEscapedNewlinesLeft: 'true'
|
||||
AlignOperands: 'false'
|
||||
AlignTrailingComments: 'true'
|
||||
AllowShortBlocksOnASingleLine: 'false'
|
||||
AllowShortCaseLabelsOnASingleLine: 'false'
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: 'false'
|
||||
AllowShortLoopsOnASingleLine: 'false'
|
||||
AlwaysBreakTemplateDeclarations: 'true'
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeTernaryOperators: 'true'
|
||||
BreakConstructorInitializersBeforeComma: 'true'
|
||||
Cpp11BracedListStyle: 'true'
|
||||
KeepEmptyLinesAtTheStartOfBlocks: 'false'
|
||||
NamespaceIndentation: All
|
||||
PenaltyBreakString: '3'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpacesInAngles: 'false'
|
||||
SpacesInContainerLiterals: 'false'
|
||||
SpacesInParentheses: 'false'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
Standard: Cpp11
|
||||
UseTab: Never
|
||||
SortIncludes: false
|
||||
ColumnLimit: 100
|
||||
|
||||
# treat pointers and reference declarations as if part of the type
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
|
||||
# when wrapping function calls/declarations, force each parameter to have its own line
|
||||
BinPackParameters: 'false'
|
||||
BinPackArguments: 'false'
|
||||
|
|
@ -1,2 +1 @@
|
|||
flutter 2.2.1
|
||||
cmake 3.20.4
|
||||
flutter 3.0.1
|
||||
|
|
|
@ -9,7 +9,7 @@ An app to interact with Lokinet as a vpn tunnel for android
|
|||
|
||||
build requirements:
|
||||
|
||||
* flutter
|
||||
* flutter 3.x (assuming google does not break it again)
|
||||
* gnu make
|
||||
* cmake
|
||||
* pkg-config
|
||||
|
|
|
@ -27,7 +27,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
|||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
|
||||
ndkVersion "21.3.6528147"
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/bin/bash
|
||||
flutter format .
|
||||
cd lokinet_lib/android && gradle spotlessApply
|
||||
clang-format -i $(find lokinet_lib/android/src/main/java/ | grep \\.java$ )
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#Mon Mar 22 01:39:44 CET 2021
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
@ -2,26 +2,26 @@ group "io.oxen.lokinet_lib"
|
|||
version "1.0-SNAPSHOT"
|
||||
|
||||
buildscript {
|
||||
ext.gradle_version = "7.2.0"
|
||||
ext.kotlin_version = "1.6.10"
|
||||
ext.spotless_version = "6.6.1"
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
maven {
|
||||
url "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath "com.android.tools.build:gradle:7.0.0"
|
||||
classpath "com.android.tools.build:gradle:$gradle_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "com.diffplug.spotless:spotless-plugin-gradle:5.14.0"
|
||||
classpath "com.diffplug.spotless:spotless-plugin-gradle:$spotless_version"
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
apply plugin: "com.diffplug.spotless"
|
||||
|
@ -29,13 +29,7 @@ apply plugin: "com.android.library"
|
|||
apply plugin: "kotlin-android"
|
||||
|
||||
spotless {
|
||||
java {
|
||||
target "$projectDir/src/main/java/**/*.java"
|
||||
importOrder() // standard import order
|
||||
removeUnusedImports()
|
||||
googleJavaFormat()
|
||||
prettier()
|
||||
}
|
||||
|
||||
groovyGradle {
|
||||
importOrder()
|
||||
target '*.gradle' // default target of groovyGradle
|
||||
|
@ -51,7 +45,14 @@ spotless {
|
|||
android {
|
||||
compileSdkVersion 31
|
||||
|
||||
packagingOptions {
|
||||
jniLibs {
|
||||
useLegacyPackaging = false
|
||||
}
|
||||
}
|
||||
|
||||
ndkVersion '21.3.6528147'
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += "src/main/java"
|
||||
main.java.srcDirs += "src/main/kotlin"
|
||||
|
@ -63,6 +64,7 @@ android {
|
|||
lintOptions {
|
||||
disable "InvalidPackage"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.bundle.enableUncompressedNativeLibs=false
|
||||
android.enableJetifier=true
|
|
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
|
|
|
@ -2,8 +2,10 @@ package network.loki.lokinet;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class LokinetConfig {
|
||||
static {
|
||||
public class LokinetConfig
|
||||
{
|
||||
static
|
||||
{
|
||||
System.loadLibrary("lokinet-android");
|
||||
}
|
||||
|
||||
|
@ -21,13 +23,17 @@ public class LokinetConfig {
|
|||
|
||||
private final ByteBuffer impl;
|
||||
|
||||
public LokinetConfig(String dataDir) {
|
||||
public LokinetConfig(String dataDir)
|
||||
{
|
||||
impl = Obtain(dataDir);
|
||||
if (impl == null) throw new RuntimeException("cannot obtain config from " + dataDir);
|
||||
if (impl == null)
|
||||
throw new RuntimeException("cannot obtain config from " + dataDir);
|
||||
}
|
||||
|
||||
public void finalize() {
|
||||
if (impl != null) {
|
||||
public void finalize()
|
||||
{
|
||||
if (impl != null)
|
||||
{
|
||||
Free(impl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ import java.util.ArrayList;
|
|||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class LokinetDaemon extends VpnService {
|
||||
|
||||
public class LokinetDaemon extends VpnService
|
||||
{
|
||||
public static final String ACTION_CONNECT = "network.loki.lokinet.START";
|
||||
public static final String ACTION_DISCONNECT = "network.loki.lokinet.STOP";
|
||||
public static final String LOG_TAG = "LokinetDaemon";
|
||||
|
@ -26,7 +26,8 @@ public class LokinetDaemon extends VpnService {
|
|||
private static final String DEFAULT_EXIT_NODE = "exit.loki";
|
||||
private static final String DEFAULT_UPSTREAM_DNS = "9.9.9.9";
|
||||
|
||||
static {
|
||||
static
|
||||
{
|
||||
System.loadLibrary("lokinet-android");
|
||||
}
|
||||
|
||||
|
@ -58,17 +59,18 @@ public class LokinetDaemon extends VpnService {
|
|||
private Timer mUpdateIsConnectedTimer;
|
||||
private MutableLiveData<Boolean> isConnected = new MutableLiveData<Boolean>();
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
@Override public void onCreate()
|
||||
{
|
||||
isConnected.postValue(false);
|
||||
mUpdateIsConnectedTimer = new Timer();
|
||||
mUpdateIsConnectedTimer.schedule(new UpdateIsConnectedTask(), 0, 500);
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (mUpdateIsConnectedTimer != null) {
|
||||
@Override public void onDestroy()
|
||||
{
|
||||
if (mUpdateIsConnectedTimer != null)
|
||||
{
|
||||
mUpdateIsConnectedTimer.cancel();
|
||||
mUpdateIsConnectedTimer = null;
|
||||
}
|
||||
|
@ -77,16 +79,19 @@ public class LokinetDaemon extends VpnService {
|
|||
disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startID) {
|
||||
@Override public int onStartCommand(Intent intent, int flags, int startID)
|
||||
{
|
||||
Log.d(LOG_TAG, "onStartCommand()");
|
||||
|
||||
String action = intent != null ? intent.getAction() : "";
|
||||
|
||||
if (ACTION_DISCONNECT.equals(action)) {
|
||||
if (ACTION_DISCONNECT.equals(action))
|
||||
{
|
||||
disconnect();
|
||||
return START_NOT_STICKY;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ArrayList<ConfigValue> configVals = new ArrayList<ConfigValue>();
|
||||
|
||||
String exitNode = null;
|
||||
|
@ -94,7 +99,8 @@ public class LokinetDaemon extends VpnService {
|
|||
|
||||
SharedPreferences sharedPreferences = getSharedPreferences("lokinet_lib", MODE_PRIVATE);
|
||||
|
||||
if (ACTION_CONNECT.equals(action)) { // started by the app
|
||||
if (ACTION_CONNECT.equals(action))
|
||||
{ // started by the app
|
||||
exitNode = intent.getStringExtra(EXIT_NODE);
|
||||
upstreamDNS = intent.getStringExtra(UPSTREAM_DNS);
|
||||
// save values
|
||||
|
@ -102,13 +108,16 @@ public class LokinetDaemon extends VpnService {
|
|||
editor.putString(EXIT_NODE, exitNode);
|
||||
editor.putString(UPSTREAM_DNS, upstreamDNS);
|
||||
editor.commit();
|
||||
} else { // if started by the system because Always-on VPN setting is enabled
|
||||
}
|
||||
else
|
||||
{ // if started by the system because Always-on VPN setting is enabled
|
||||
// use the latest values
|
||||
exitNode = sharedPreferences.getString(EXIT_NODE, null);
|
||||
upstreamDNS = sharedPreferences.getString(UPSTREAM_DNS, null);
|
||||
}
|
||||
|
||||
if (exitNode == null || exitNode.isEmpty()) {
|
||||
if (exitNode == null || exitNode.isEmpty())
|
||||
{
|
||||
exitNode = DEFAULT_EXIT_NODE;
|
||||
Log.e(LOG_TAG, "No exit-node configured! Proceeding with default.");
|
||||
}
|
||||
|
@ -116,7 +125,8 @@ public class LokinetDaemon extends VpnService {
|
|||
Log.e(LOG_TAG, "Using " + exitNode + " as exit-node.");
|
||||
configVals.add(new ConfigValue("network", "exit-node", exitNode));
|
||||
|
||||
if (upstreamDNS == null || upstreamDNS.isEmpty()) {
|
||||
if (upstreamDNS == null || upstreamDNS.isEmpty())
|
||||
{
|
||||
upstreamDNS = DEFAULT_UPSTREAM_DNS;
|
||||
Log.e(LOG_TAG, "No upstream DNS configured! Proceeding with default.");
|
||||
}
|
||||
|
@ -135,25 +145,28 @@ public class LokinetDaemon extends VpnService {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRevoke() {
|
||||
@Override public void onRevoke()
|
||||
{
|
||||
Log.d(LOG_TAG, "onRevoke()");
|
||||
disconnect();
|
||||
super.onRevoke();
|
||||
}
|
||||
|
||||
private class ConfigValue {
|
||||
private class ConfigValue
|
||||
{
|
||||
final String Section;
|
||||
final String Key;
|
||||
final String Value;
|
||||
|
||||
public ConfigValue(String section, String key, String value) {
|
||||
public ConfigValue(String section, String key, String value)
|
||||
{
|
||||
Section = section;
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public boolean Valid() {
|
||||
public boolean Valid()
|
||||
{
|
||||
if (Section == null || Key == null || Value == null)
|
||||
return false;
|
||||
if (Section.isEmpty() || Key.isEmpty() || Value.isEmpty())
|
||||
|
@ -162,30 +175,38 @@ public class LokinetDaemon extends VpnService {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean connect(ArrayList<ConfigValue> configVals) {
|
||||
if (!IsRunning()) {
|
||||
if (impl != null) {
|
||||
private boolean connect(ArrayList<ConfigValue> configVals)
|
||||
{
|
||||
if (!IsRunning())
|
||||
{
|
||||
if (impl != null)
|
||||
{
|
||||
Free(impl);
|
||||
impl = null;
|
||||
}
|
||||
impl = Obtain();
|
||||
if (impl == null) {
|
||||
if (impl == null)
|
||||
{
|
||||
Log.e(LOG_TAG, "got nullptr when creating llarp::Context in jni");
|
||||
return false;
|
||||
}
|
||||
|
||||
String dataDir = getFilesDir().toString();
|
||||
LokinetConfig config;
|
||||
try {
|
||||
try
|
||||
{
|
||||
config = new LokinetConfig(dataDir);
|
||||
} catch (RuntimeException ex) {
|
||||
}
|
||||
catch (RuntimeException ex)
|
||||
{
|
||||
Log.e(LOG_TAG, ex.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
String ourRange = DetectFreeRange();
|
||||
|
||||
if (ourRange.isEmpty()) {
|
||||
if (ourRange.isEmpty())
|
||||
{
|
||||
Log.e(LOG_TAG, "cannot detect free range");
|
||||
return false;
|
||||
}
|
||||
|
@ -193,22 +214,28 @@ public class LokinetDaemon extends VpnService {
|
|||
String upstreamDNS = DEFAULT_UPSTREAM_DNS;
|
||||
|
||||
// set up config values
|
||||
if (configVals != null) {
|
||||
configVals.add(new ConfigValue("network", "ifaddr", ourRange));
|
||||
for (ConfigValue conf : configVals) {
|
||||
if (conf.Valid()) {
|
||||
config.AddDefaultValue(conf.Section, conf.Key, conf.Value);
|
||||
if (conf.Section.equals("dns") && conf.Key.equals("upstream"))
|
||||
upstreamDNS = conf.Value;
|
||||
}
|
||||
if (configVals == null)
|
||||
{
|
||||
configVals = new ArrayList<ConfigValue>();
|
||||
}
|
||||
|
||||
configVals.add(new ConfigValue("network", "ifaddr", ourRange));
|
||||
configVals.add(new ConfigValue("network", "ip6-range", "fd00::/112"));
|
||||
for (ConfigValue conf : configVals)
|
||||
{
|
||||
if (conf.Valid())
|
||||
{
|
||||
config.AddDefaultValue(conf.Section, conf.Key, conf.Value);
|
||||
if (conf.Section.equals("dns") && conf.Key.equals("upstream"))
|
||||
upstreamDNS = conf.Value;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.Load()) {
|
||||
if (!config.Load())
|
||||
{
|
||||
Log.e(
|
||||
LOG_TAG,
|
||||
"failed to load (or create) config file at: "
|
||||
+ dataDir
|
||||
"failed to load (or create) config file at: " + dataDir
|
||||
+ "/loki.network.loki.lokinet.ini");
|
||||
return false;
|
||||
}
|
||||
|
@ -222,6 +249,8 @@ public class LokinetDaemon extends VpnService {
|
|||
int ourMask = Integer.parseInt(parts[1]);
|
||||
|
||||
builder.addAddress(ourIP, ourMask);
|
||||
builder.addAddress("fd00::1", 112);
|
||||
|
||||
builder.addRoute("0.0.0.0", 0);
|
||||
builder.addRoute("::", 0);
|
||||
builder.addDnsServer(upstreamDNS);
|
||||
|
@ -229,7 +258,8 @@ public class LokinetDaemon extends VpnService {
|
|||
builder.setConfigureIntent(null);
|
||||
|
||||
iface = builder.establish();
|
||||
if (iface == null) {
|
||||
if (iface == null)
|
||||
{
|
||||
Log.e(LOG_TAG, "VPN Interface from builder.establish() came back null");
|
||||
return false;
|
||||
}
|
||||
|
@ -237,25 +267,27 @@ public class LokinetDaemon extends VpnService {
|
|||
m_FD = iface.detachFd();
|
||||
|
||||
InjectVPNFD();
|
||||
new Thread(
|
||||
() -> {
|
||||
Configure(config);
|
||||
m_UDPSocket = GetUDPSocket();
|
||||
protect(m_UDPSocket);
|
||||
Mainloop();
|
||||
})
|
||||
.start();
|
||||
new Thread(() -> {
|
||||
Configure(config);
|
||||
m_UDPSocket = GetUDPSocket();
|
||||
protect(m_UDPSocket);
|
||||
Mainloop();
|
||||
}).start();
|
||||
|
||||
Log.d(LOG_TAG, "started successfully!");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.d(LOG_TAG, "already running");
|
||||
}
|
||||
updateIsConnected();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void disconnect() {
|
||||
if (IsRunning()) {
|
||||
private void disconnect()
|
||||
{
|
||||
if (IsRunning())
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
// if (impl != null) {
|
||||
|
@ -265,11 +297,13 @@ public class LokinetDaemon extends VpnService {
|
|||
updateIsConnected();
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> isConnected() {
|
||||
public MutableLiveData<Boolean> isConnected()
|
||||
{
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
private void updateIsConnected() {
|
||||
private void updateIsConnected()
|
||||
{
|
||||
isConnected.postValue(IsRunning() && VpnService.prepare(LokinetDaemon.this) == null);
|
||||
}
|
||||
|
||||
|
@ -277,17 +311,20 @@ public class LokinetDaemon extends VpnService {
|
|||
* Class for clients to access. Because we know this service always runs in the
|
||||
* same process as its clients, we don't need to deal with IPC.
|
||||
*/
|
||||
public class LocalBinder extends Binder {
|
||||
public LokinetDaemon getService() {
|
||||
public class LocalBinder extends Binder
|
||||
{
|
||||
public LokinetDaemon getService()
|
||||
{
|
||||
return LokinetDaemon.this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
@Override public IBinder onBind(Intent intent)
|
||||
{
|
||||
String action = intent != null ? intent.getAction() : "";
|
||||
|
||||
if (VpnService.SERVICE_INTERFACE.equals(action)) {
|
||||
if (VpnService.SERVICE_INTERFACE.equals(action))
|
||||
{
|
||||
return super.onBind(intent);
|
||||
}
|
||||
|
||||
|
@ -296,9 +333,11 @@ public class LokinetDaemon extends VpnService {
|
|||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
private class UpdateIsConnectedTask extends TimerTask {
|
||||
public void run() {
|
||||
private class UpdateIsConnectedTask extends TimerTask
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
updateIsConnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 27d883157d4cb319a32e705168345e2a8ca9f32b
|
||||
Subproject commit 608dced827c92645ce74478378985400cb104a6f
|
18
pubspec.lock
18
pubspec.lock
|
@ -56,7 +56,7 @@ packages:
|
|||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.16.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -84,7 +84,7 @@ packages:
|
|||
name: fake_async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.3.0"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -134,7 +134,7 @@ packages:
|
|||
name: js
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.3"
|
||||
version: "0.6.4"
|
||||
lokinet_lib:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -155,7 +155,7 @@ packages:
|
|||
name: material_color_utilities
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
version: "0.1.4"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -169,7 +169,7 @@ packages:
|
|||
name: path
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0"
|
||||
version: "1.8.1"
|
||||
path_provider:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -286,7 +286,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.1"
|
||||
version: "1.8.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -321,7 +321,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.8"
|
||||
version: "0.4.9"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -335,7 +335,7 @@ packages:
|
|||
name: vector_math
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -365,5 +365,5 @@ packages:
|
|||
source: hosted
|
||||
version: "2.2.1"
|
||||
sdks:
|
||||
dart: ">=2.15.0 <3.0.0"
|
||||
dart: ">=2.17.0-0 <3.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
|
Loading…
Reference in New Issue