Add 'client/' from commit '92f38b581074e4562102327b12425e3df4695e54'

git-subtree-dir: client
git-subtree-mainline: 024017338e
git-subtree-split: 92f38b5810
This commit is contained in:
mitchell 2019-07-11 02:41:03 -04:00
commit 66ec035ee0
90 changed files with 3817 additions and 0 deletions

70
client/.gitignore vendored Normal file
View File

@ -0,0 +1,70 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.vscode/
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.packages
.pub-cache/
.pub/
/build/
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

10
client/.metadata Normal file
View File

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b
channel: stable
project_type: app

3
client/README.md Normal file
View File

@ -0,0 +1,3 @@
# selfpass_client
This is the multi-platform native Selfpass client built with the Flutter framework.

View File

@ -0,0 +1,61 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 28
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.mjfs.selfpass"
minSdkVersion 16
targetSdkVersion 28
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mjfs.selfpass">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,33 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mjfs.selfpass">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="selfpass_client"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,13 @@
package com.example.selfpass_mobile;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
</resources>

View File

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mjfs.selfpass">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,29 @@
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@ -0,0 +1 @@
org.gradle.jvmargs=-Xmx1536M

View File

@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

View File

@ -0,0 +1,15 @@
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}

BIN
client/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

BIN
client/app.xcf Normal file

Binary file not shown.

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>

View File

@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View File

@ -0,0 +1,2 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

69
client/ios/Podfile Normal file
View File

@ -0,0 +1,69 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
pods_ary = []
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) { |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
pods_ary.push({:name => podname, :path => podpath});
else
puts "Invalid plugin specification: #{line}"
end
}
return pods_ary
end
target 'Runner' do
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
# Flutter Pods
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
if generated_xcode_build_settings.empty?
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
end
generated_xcode_build_settings.map { |p|
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
symlink = File.join('.symlinks', 'flutter')
File.symlink(File.dirname(p[:path]), symlink)
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
end
}
# Plugin Pods
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.map { |p|
symlink = File.join('.symlinks', 'plugins', p[:name])
File.symlink(p[:path], symlink)
pod p[:name], :path => File.join(symlink, 'ios')
}
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end

22
client/ios/Podfile.lock Normal file
View File

@ -0,0 +1,22 @@
PODS:
- Flutter (1.0.0)
- flutter_secure_storage (3.2.0):
- Flutter
DEPENDENCIES:
- Flutter (from `.symlinks/flutter/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
EXTERNAL SOURCES:
Flutter:
:path: ".symlinks/flutter/ios"
flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
SPEC CHECKSUMS:
Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a
flutter_secure_storage: 0c5779648ff644110e507909b77a57e620cbbf8b
PODFILE CHECKSUM: aff02bfeed411c636180d6812254b2daeea14d09
COCOAPODS: 1.7.2

View File

@ -0,0 +1,587 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
F8EF57AFFF0C7C353E3604B3 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 097444538E941EBFED1976C8 /* libPods-Runner.a */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
097444538E941EBFED1976C8 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
4674E99068360BD2489EC50C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
880DAEE09FC4F07D8ED7F46C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A4F4986515B0C16B78A73BD7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
F8EF57AFFF0C7C353E3604B3 /* libPods-Runner.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
D52790F7E6421775A2150276 /* Pods */,
E491E94631566224F7EB2248 /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
97C146F21CF9000F007C117D /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
D52790F7E6421775A2150276 /* Pods */ = {
isa = PBXGroup;
children = (
880DAEE09FC4F07D8ED7F46C /* Pods-Runner.debug.xcconfig */,
A4F4986515B0C16B78A73BD7 /* Pods-Runner.release.xcconfig */,
4674E99068360BD2489EC50C /* Pods-Runner.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
E491E94631566224F7EB2248 /* Frameworks */ = {
isa = PBXGroup;
children = (
097444538E941EBFED1976C8 /* libPods-Runner.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
0D0C54F13DCFB588B50287A7 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
273F25DC0E60392B1958115D /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = D8G6NQ28ZR;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
0D0C54F13DCFB588B50287A7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
273F25DC0E60392B1958115D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */,
97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Profile;
};
249021D4217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = D8G6NQ28ZR;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mjfs.selfpass;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = D8G6NQ28ZR;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mjfs.selfpass;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
97C147071CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = D8G6NQ28ZR;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mjfs.selfpass;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
</dict>
</plist>

View File

@ -0,0 +1,6 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate
@end

View File

@ -0,0 +1,13 @@
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[GeneratedPluginRegistrant registerWithRegistry:self];
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,140 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "40.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "60.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "58.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "87.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "80.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "120.png",
"scale" : "3x"
},
{
"size" : "57x57",
"idiom" : "iphone",
"filename" : "57.png",
"scale" : "1x"
},
{
"size" : "57x57",
"idiom" : "iphone",
"filename" : "114.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "120.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "180.png",
"scale" : "3x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "1024.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "16.png",
"scale" : "1x"
},
{
"size" : "16x16",
"idiom" : "mac",
"filename" : "32.png",
"scale" : "2x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "32.png",
"scale" : "1x"
},
{
"size" : "32x32",
"idiom" : "mac",
"filename" : "64.png",
"scale" : "2x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "128.png",
"scale" : "1x"
},
{
"size" : "128x128",
"idiom" : "mac",
"filename" : "256.png",
"scale" : "2x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "256.png",
"scale" : "1x"
},
{
"size" : "256x256",
"idiom" : "mac",
"filename" : "512.png",
"scale" : "2x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "512.png",
"scale" : "1x"
},
{
"size" : "512x512",
"idiom" : "mac",
"filename" : "1024-1.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>Selfpass</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>selfpass_client</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

9
client/ios/Runner/main.m Normal file
View File

@ -0,0 +1,9 @@
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

78
client/lib/main.dart Normal file
View File

@ -0,0 +1,78 @@
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'repositories/grpc_credentials_client.dart';
import 'repositories/secure_storage_config.dart';
import 'screens/authentication.dart';
import 'screens/credential.dart';
import 'screens/credentials.dart';
import 'screens/config.dart';
import 'screens/home.dart';
import 'types/abstracts.dart';
import 'types/screen_arguments.dart';
void main() => runApp(Selfpass());
class Selfpass extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Provider<ConfigRepo>(
builder: (BuildContext context) => SecureStorageConfig(),
child: CupertinoApp(
title: 'Selfpass',
onGenerateRoute: (RouteSettings settings) {
String title;
WidgetBuilder builder;
switch (settings.name) {
case '/':
title = 'Authentication';
builder = (BuildContext context) => Authentication();
break;
case '/home':
title = 'Hosts';
builder = (BuildContext context) => Provider<CredentialsRepo>(
builder: (BuildContext context) =>
GRPCCredentialsClient.cached(config: settings.arguments),
child: Home(),
);
break;
case '/credentials':
title = 'Credentials';
builder = (BuildContext context) => Provider<CredentialsRepo>(
builder: (BuildContext context) =>
GRPCCredentialsClient.cached(),
child: Credentials(settings.arguments),
);
break;
case '/credential':
title = 'Credential';
builder = (BuildContext context) => Provider<CredentialsRepo>(
builder: (BuildContext context) =>
GRPCCredentialsClient.cached(),
child: Credential(settings.arguments),
);
break;
case '/config':
final ConfigScreenArguments arguments = settings.arguments == null
? ConfigScreenArguments()
: settings.arguments;
title = 'Configuration';
builder = (BuildContext context) =>
Config(arguments.connectionConfig, arguments.privateKey);
break;
}
return CupertinoPageRoute(builder: builder, title: title);
},
),
);
}
}

View File

@ -0,0 +1,74 @@
///
// Generated code. Do not modify.
// source: timestamp.proto
///
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name
import 'dart:core' as $core
show bool, Deprecated, double, int, List, Map, override, pragma, String;
import 'package:fixnum/fixnum.dart';
import 'package:protobuf/protobuf.dart' as $pb;
import 'dart:core' as $core show DateTime, Duration;
class Timestamp extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('Timestamp',
package: const $pb.PackageName('google.protobuf'))
..aInt64(1, 'seconds')
..a<$core.int>(2, 'nanos', $pb.PbFieldType.O3)
..hasRequiredFields = false;
Timestamp._() : super();
factory Timestamp() => create();
factory Timestamp.fromBuffer($core.List<$core.int> i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromBuffer(i, r);
factory Timestamp.fromJson($core.String i,
[$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
create()..mergeFromJson(i, r);
Timestamp clone() => Timestamp()..mergeFromMessage(this);
Timestamp copyWith(void Function(Timestamp) updates) =>
super.copyWith((message) => updates(message as Timestamp));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static Timestamp create() => Timestamp._();
Timestamp createEmptyInstance() => create();
static $pb.PbList<Timestamp> createRepeated() => $pb.PbList<Timestamp>();
static Timestamp getDefault() => _defaultInstance ??= create()..freeze();
static Timestamp _defaultInstance;
Int64 get seconds => $_getI64(0);
set seconds(Int64 v) {
$_setInt64(0, v);
}
$core.bool hasSeconds() => $_has(0);
void clearSeconds() => clearField(1);
$core.int get nanos => $_get(1, 0);
set nanos($core.int v) {
$_setSignedInt32(1, v);
}
$core.bool hasNanos() => $_has(1);
void clearNanos() => clearField(2);
/// Converts an instance to [DateTime].
///
/// The result is in UTC time zone and has microsecond precision, as
/// [DateTime] does not support nanosecond precision.
$core.DateTime toDateTime() => $core.DateTime.fromMicrosecondsSinceEpoch(
seconds.toInt() * $core.Duration.microsecondsPerSecond + nanos ~/ 1000,
isUtc: true);
/// Creates a new instance from [dateTime].
///
/// Time zone information will not be preserved.
static Timestamp fromDateTime($core.DateTime dateTime) {
$core.int micros = dateTime.microsecondsSinceEpoch;
return Timestamp()
..seconds = Int64(micros ~/ $core.Duration.microsecondsPerSecond)
..nanos = (micros % $core.Duration.microsecondsPerSecond).toInt() * 1000;
}
}

View File

@ -0,0 +1,6 @@
///
// Generated code. Do not modify.
// source: timestamp.proto
///
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name

View File

@ -0,0 +1,13 @@
///
// Generated code. Do not modify.
// source: timestamp.proto
///
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name
const Timestamp$json = const {
'1': 'Timestamp',
'2': const [
const {'1': 'seconds', '3': 1, '4': 1, '5': 3, '10': 'seconds'},
const {'1': 'nanos', '3': 2, '4': 1, '5': 5, '10': 'nanos'},
],
};

View File

@ -0,0 +1,384 @@
///
// Generated code. Do not modify.
// source: service.proto
///
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name
import 'dart:core' as $core show bool, Deprecated, double, int, List, Map, override, pragma, String;
import 'package:protobuf/protobuf.dart' as $pb;
import 'google/protobuf/timestamp.pb.dart' as $1;
class DeleteResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('DeleteResponse', package: const $pb.PackageName('selfpass.credentials'))
..aOB(1, 'success')
..hasRequiredFields = false
;
DeleteResponse._() : super();
factory DeleteResponse() => create();
factory DeleteResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory DeleteResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
DeleteResponse clone() => DeleteResponse()..mergeFromMessage(this);
DeleteResponse copyWith(void Function(DeleteResponse) updates) => super.copyWith((message) => updates(message as DeleteResponse));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static DeleteResponse create() => DeleteResponse._();
DeleteResponse createEmptyInstance() => create();
static $pb.PbList<DeleteResponse> createRepeated() => $pb.PbList<DeleteResponse>();
static DeleteResponse getDefault() => _defaultInstance ??= create()..freeze();
static DeleteResponse _defaultInstance;
$core.bool get success => $_get(0, false);
set success($core.bool v) { $_setBool(0, v); }
$core.bool hasSuccess() => $_has(0);
void clearSuccess() => clearField(1);
}
class GetAllMetadataRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('GetAllMetadataRequest', package: const $pb.PackageName('selfpass.credentials'))
..aOS(1, 'sourceHost')
..hasRequiredFields = false
;
GetAllMetadataRequest._() : super();
factory GetAllMetadataRequest() => create();
factory GetAllMetadataRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory GetAllMetadataRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
GetAllMetadataRequest clone() => GetAllMetadataRequest()..mergeFromMessage(this);
GetAllMetadataRequest copyWith(void Function(GetAllMetadataRequest) updates) => super.copyWith((message) => updates(message as GetAllMetadataRequest));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GetAllMetadataRequest create() => GetAllMetadataRequest._();
GetAllMetadataRequest createEmptyInstance() => create();
static $pb.PbList<GetAllMetadataRequest> createRepeated() => $pb.PbList<GetAllMetadataRequest>();
static GetAllMetadataRequest getDefault() => _defaultInstance ??= create()..freeze();
static GetAllMetadataRequest _defaultInstance;
$core.String get sourceHost => $_getS(0, '');
set sourceHost($core.String v) { $_setString(0, v); }
$core.bool hasSourceHost() => $_has(0);
void clearSourceHost() => clearField(1);
}
class IdRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('IdRequest', package: const $pb.PackageName('selfpass.credentials'))
..aOS(1, 'id')
..hasRequiredFields = false
;
IdRequest._() : super();
factory IdRequest() => create();
factory IdRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory IdRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
IdRequest clone() => IdRequest()..mergeFromMessage(this);
IdRequest copyWith(void Function(IdRequest) updates) => super.copyWith((message) => updates(message as IdRequest));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static IdRequest create() => IdRequest._();
IdRequest createEmptyInstance() => create();
static $pb.PbList<IdRequest> createRepeated() => $pb.PbList<IdRequest>();
static IdRequest getDefault() => _defaultInstance ??= create()..freeze();
static IdRequest _defaultInstance;
$core.String get id => $_getS(0, '');
set id($core.String v) { $_setString(0, v); }
$core.bool hasId() => $_has(0);
void clearId() => clearField(1);
}
class UpdateRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('UpdateRequest', package: const $pb.PackageName('selfpass.credentials'))
..aOS(1, 'id')
..a<CredentialRequest>(2, 'credential', $pb.PbFieldType.OM, CredentialRequest.getDefault, CredentialRequest.create)
..hasRequiredFields = false
;
UpdateRequest._() : super();
factory UpdateRequest() => create();
factory UpdateRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory UpdateRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
UpdateRequest clone() => UpdateRequest()..mergeFromMessage(this);
UpdateRequest copyWith(void Function(UpdateRequest) updates) => super.copyWith((message) => updates(message as UpdateRequest));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static UpdateRequest create() => UpdateRequest._();
UpdateRequest createEmptyInstance() => create();
static $pb.PbList<UpdateRequest> createRepeated() => $pb.PbList<UpdateRequest>();
static UpdateRequest getDefault() => _defaultInstance ??= create()..freeze();
static UpdateRequest _defaultInstance;
$core.String get id => $_getS(0, '');
set id($core.String v) { $_setString(0, v); }
$core.bool hasId() => $_has(0);
void clearId() => clearField(1);
CredentialRequest get credential => $_getN(1);
set credential(CredentialRequest v) { setField(2, v); }
$core.bool hasCredential() => $_has(1);
void clearCredential() => clearField(2);
}
class DumpResponse extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('DumpResponse', package: const $pb.PackageName('selfpass.credentials'))
..a<$core.List<$core.int>>(1, 'contents', $pb.PbFieldType.OY)
..hasRequiredFields = false
;
DumpResponse._() : super();
factory DumpResponse() => create();
factory DumpResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory DumpResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
DumpResponse clone() => DumpResponse()..mergeFromMessage(this);
DumpResponse copyWith(void Function(DumpResponse) updates) => super.copyWith((message) => updates(message as DumpResponse));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static DumpResponse create() => DumpResponse._();
DumpResponse createEmptyInstance() => create();
static $pb.PbList<DumpResponse> createRepeated() => $pb.PbList<DumpResponse>();
static DumpResponse getDefault() => _defaultInstance ??= create()..freeze();
static DumpResponse _defaultInstance;
$core.List<$core.int> get contents => $_getN(0);
set contents($core.List<$core.int> v) { $_setBytes(0, v); }
$core.bool hasContents() => $_has(0);
void clearContents() => clearField(1);
}
class EmptyRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('EmptyRequest', package: const $pb.PackageName('selfpass.credentials'))
..hasRequiredFields = false
;
EmptyRequest._() : super();
factory EmptyRequest() => create();
factory EmptyRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory EmptyRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
EmptyRequest clone() => EmptyRequest()..mergeFromMessage(this);
EmptyRequest copyWith(void Function(EmptyRequest) updates) => super.copyWith((message) => updates(message as EmptyRequest));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static EmptyRequest create() => EmptyRequest._();
EmptyRequest createEmptyInstance() => create();
static $pb.PbList<EmptyRequest> createRepeated() => $pb.PbList<EmptyRequest>();
static EmptyRequest getDefault() => _defaultInstance ??= create()..freeze();
static EmptyRequest _defaultInstance;
}
class Metadata extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('Metadata', package: const $pb.PackageName('selfpass.credentials'))
..aOS(1, 'id')
..a<$1.Timestamp>(2, 'createdAt', $pb.PbFieldType.OM, $1.Timestamp.getDefault, $1.Timestamp.create)
..a<$1.Timestamp>(3, 'updatedAt', $pb.PbFieldType.OM, $1.Timestamp.getDefault, $1.Timestamp.create)
..aOS(4, 'primary')
..aOS(5, 'sourceHost')
..aOS(6, 'loginUrl')
..aOS(7, 'tag')
..hasRequiredFields = false
;
Metadata._() : super();
factory Metadata() => create();
factory Metadata.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory Metadata.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
Metadata clone() => Metadata()..mergeFromMessage(this);
Metadata copyWith(void Function(Metadata) updates) => super.copyWith((message) => updates(message as Metadata));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static Metadata create() => Metadata._();
Metadata createEmptyInstance() => create();
static $pb.PbList<Metadata> createRepeated() => $pb.PbList<Metadata>();
static Metadata getDefault() => _defaultInstance ??= create()..freeze();
static Metadata _defaultInstance;
$core.String get id => $_getS(0, '');
set id($core.String v) { $_setString(0, v); }
$core.bool hasId() => $_has(0);
void clearId() => clearField(1);
$1.Timestamp get createdAt => $_getN(1);
set createdAt($1.Timestamp v) { setField(2, v); }
$core.bool hasCreatedAt() => $_has(1);
void clearCreatedAt() => clearField(2);
$1.Timestamp get updatedAt => $_getN(2);
set updatedAt($1.Timestamp v) { setField(3, v); }
$core.bool hasUpdatedAt() => $_has(2);
void clearUpdatedAt() => clearField(3);
$core.String get primary => $_getS(3, '');
set primary($core.String v) { $_setString(3, v); }
$core.bool hasPrimary() => $_has(3);
void clearPrimary() => clearField(4);
$core.String get sourceHost => $_getS(4, '');
set sourceHost($core.String v) { $_setString(4, v); }
$core.bool hasSourceHost() => $_has(4);
void clearSourceHost() => clearField(5);
$core.String get loginUrl => $_getS(5, '');
set loginUrl($core.String v) { $_setString(5, v); }
$core.bool hasLoginUrl() => $_has(5);
void clearLoginUrl() => clearField(6);
$core.String get tag => $_getS(6, '');
set tag($core.String v) { $_setString(6, v); }
$core.bool hasTag() => $_has(6);
void clearTag() => clearField(7);
}
class Credential extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('Credential', package: const $pb.PackageName('selfpass.credentials'))
..aOS(1, 'id')
..a<$1.Timestamp>(2, 'createdAt', $pb.PbFieldType.OM, $1.Timestamp.getDefault, $1.Timestamp.create)
..a<$1.Timestamp>(3, 'updatedAt', $pb.PbFieldType.OM, $1.Timestamp.getDefault, $1.Timestamp.create)
..aOS(4, 'primary')
..aOS(5, 'username')
..aOS(6, 'email')
..aOS(7, 'password')
..aOS(8, 'sourceHost')
..aOS(9, 'loginUrl')
..aOS(10, 'tag')
..aOS(11, 'otpSecret')
..hasRequiredFields = false
;
Credential._() : super();
factory Credential() => create();
factory Credential.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory Credential.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
Credential clone() => Credential()..mergeFromMessage(this);
Credential copyWith(void Function(Credential) updates) => super.copyWith((message) => updates(message as Credential));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static Credential create() => Credential._();
Credential createEmptyInstance() => create();
static $pb.PbList<Credential> createRepeated() => $pb.PbList<Credential>();
static Credential getDefault() => _defaultInstance ??= create()..freeze();
static Credential _defaultInstance;
$core.String get id => $_getS(0, '');
set id($core.String v) { $_setString(0, v); }
$core.bool hasId() => $_has(0);
void clearId() => clearField(1);
$1.Timestamp get createdAt => $_getN(1);
set createdAt($1.Timestamp v) { setField(2, v); }
$core.bool hasCreatedAt() => $_has(1);
void clearCreatedAt() => clearField(2);
$1.Timestamp get updatedAt => $_getN(2);
set updatedAt($1.Timestamp v) { setField(3, v); }
$core.bool hasUpdatedAt() => $_has(2);
void clearUpdatedAt() => clearField(3);
$core.String get primary => $_getS(3, '');
set primary($core.String v) { $_setString(3, v); }
$core.bool hasPrimary() => $_has(3);
void clearPrimary() => clearField(4);
$core.String get username => $_getS(4, '');
set username($core.String v) { $_setString(4, v); }
$core.bool hasUsername() => $_has(4);
void clearUsername() => clearField(5);
$core.String get email => $_getS(5, '');
set email($core.String v) { $_setString(5, v); }
$core.bool hasEmail() => $_has(5);
void clearEmail() => clearField(6);
$core.String get password => $_getS(6, '');
set password($core.String v) { $_setString(6, v); }
$core.bool hasPassword() => $_has(6);
void clearPassword() => clearField(7);
$core.String get sourceHost => $_getS(7, '');
set sourceHost($core.String v) { $_setString(7, v); }
$core.bool hasSourceHost() => $_has(7);
void clearSourceHost() => clearField(8);
$core.String get loginUrl => $_getS(8, '');
set loginUrl($core.String v) { $_setString(8, v); }
$core.bool hasLoginUrl() => $_has(8);
void clearLoginUrl() => clearField(9);
$core.String get tag => $_getS(9, '');
set tag($core.String v) { $_setString(9, v); }
$core.bool hasTag() => $_has(9);
void clearTag() => clearField(10);
$core.String get otpSecret => $_getS(10, '');
set otpSecret($core.String v) { $_setString(10, v); }
$core.bool hasOtpSecret() => $_has(10);
void clearOtpSecret() => clearField(11);
}
class CredentialRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo('CredentialRequest', package: const $pb.PackageName('selfpass.credentials'))
..aOS(1, 'primary')
..aOS(2, 'username')
..aOS(3, 'email')
..aOS(4, 'password')
..aOS(5, 'sourceHost')
..aOS(6, 'loginUrl')
..aOS(7, 'tag')
..aOS(8, 'otpSecret')
..hasRequiredFields = false
;
CredentialRequest._() : super();
factory CredentialRequest() => create();
factory CredentialRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory CredentialRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
CredentialRequest clone() => CredentialRequest()..mergeFromMessage(this);
CredentialRequest copyWith(void Function(CredentialRequest) updates) => super.copyWith((message) => updates(message as CredentialRequest));
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static CredentialRequest create() => CredentialRequest._();
CredentialRequest createEmptyInstance() => create();
static $pb.PbList<CredentialRequest> createRepeated() => $pb.PbList<CredentialRequest>();
static CredentialRequest getDefault() => _defaultInstance ??= create()..freeze();
static CredentialRequest _defaultInstance;
$core.String get primary => $_getS(0, '');
set primary($core.String v) { $_setString(0, v); }
$core.bool hasPrimary() => $_has(0);
void clearPrimary() => clearField(1);
$core.String get username => $_getS(1, '');
set username($core.String v) { $_setString(1, v); }
$core.bool hasUsername() => $_has(1);
void clearUsername() => clearField(2);
$core.String get email => $_getS(2, '');
set email($core.String v) { $_setString(2, v); }
$core.bool hasEmail() => $_has(2);
void clearEmail() => clearField(3);
$core.String get password => $_getS(3, '');
set password($core.String v) { $_setString(3, v); }
$core.bool hasPassword() => $_has(3);
void clearPassword() => clearField(4);
$core.String get sourceHost => $_getS(4, '');
set sourceHost($core.String v) { $_setString(4, v); }
$core.bool hasSourceHost() => $_has(4);
void clearSourceHost() => clearField(5);
$core.String get loginUrl => $_getS(5, '');
set loginUrl($core.String v) { $_setString(5, v); }
$core.bool hasLoginUrl() => $_has(5);
void clearLoginUrl() => clearField(6);
$core.String get tag => $_getS(6, '');
set tag($core.String v) { $_setString(6, v); }
$core.bool hasTag() => $_has(6);
void clearTag() => clearField(7);
$core.String get otpSecret => $_getS(7, '');
set otpSecret($core.String v) { $_setString(7, v); }
$core.bool hasOtpSecret() => $_has(7);
void clearOtpSecret() => clearField(8);
}

View File

@ -0,0 +1,6 @@
///
// Generated code. Do not modify.
// source: service.proto
///
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name

View File

@ -0,0 +1,158 @@
///
// Generated code. Do not modify.
// source: service.proto
///
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name
import 'dart:async' as $async;
import 'dart:core' as $core show int, String, List;
import 'package:grpc/service_api.dart' as $grpc;
import 'service.pb.dart' as $0;
export 'service.pb.dart';
class CredentialServiceClient extends $grpc.Client {
static final _$getAllMetadata =
$grpc.ClientMethod<$0.GetAllMetadataRequest, $0.Metadata>(
'/selfpass.credentials.CredentialService/GetAllMetadata',
($0.GetAllMetadataRequest value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.Metadata.fromBuffer(value));
static final _$get = $grpc.ClientMethod<$0.IdRequest, $0.Credential>(
'/selfpass.credentials.CredentialService/Get',
($0.IdRequest value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.Credential.fromBuffer(value));
static final _$create =
$grpc.ClientMethod<$0.CredentialRequest, $0.Credential>(
'/selfpass.credentials.CredentialService/Create',
($0.CredentialRequest value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.Credential.fromBuffer(value));
static final _$update = $grpc.ClientMethod<$0.UpdateRequest, $0.Credential>(
'/selfpass.credentials.CredentialService/Update',
($0.UpdateRequest value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.Credential.fromBuffer(value));
static final _$delete = $grpc.ClientMethod<$0.IdRequest, $0.DeleteResponse>(
'/selfpass.credentials.CredentialService/Delete',
($0.IdRequest value) => value.writeToBuffer(),
($core.List<$core.int> value) => $0.DeleteResponse.fromBuffer(value));
CredentialServiceClient($grpc.ClientChannel channel,
{$grpc.CallOptions options})
: super(channel, options: options);
$grpc.ResponseStream<$0.Metadata> getAllMetadata(
$0.GetAllMetadataRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(
_$getAllMetadata, $async.Stream.fromIterable([request]),
options: options);
return $grpc.ResponseStream(call);
}
$grpc.ResponseFuture<$0.Credential> get($0.IdRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(_$get, $async.Stream.fromIterable([request]),
options: options);
return $grpc.ResponseFuture(call);
}
$grpc.ResponseFuture<$0.Credential> create($0.CredentialRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(_$create, $async.Stream.fromIterable([request]),
options: options);
return $grpc.ResponseFuture(call);
}
$grpc.ResponseFuture<$0.Credential> update($0.UpdateRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(_$update, $async.Stream.fromIterable([request]),
options: options);
return $grpc.ResponseFuture(call);
}
$grpc.ResponseFuture<$0.DeleteResponse> delete($0.IdRequest request,
{$grpc.CallOptions options}) {
final call = $createCall(_$delete, $async.Stream.fromIterable([request]),
options: options);
return $grpc.ResponseFuture(call);
}
}
abstract class CredentialServiceBase extends $grpc.Service {
$core.String get $name => 'selfpass.credentials.CredentialService';
CredentialServiceBase() {
$addMethod($grpc.ServiceMethod<$0.GetAllMetadataRequest, $0.Metadata>(
'GetAllMetadata',
getAllMetadata_Pre,
false,
true,
($core.List<$core.int> value) =>
$0.GetAllMetadataRequest.fromBuffer(value),
($0.Metadata value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.IdRequest, $0.Credential>(
'Get',
get_Pre,
false,
false,
($core.List<$core.int> value) => $0.IdRequest.fromBuffer(value),
($0.Credential value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.CredentialRequest, $0.Credential>(
'Create',
create_Pre,
false,
false,
($core.List<$core.int> value) => $0.CredentialRequest.fromBuffer(value),
($0.Credential value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.UpdateRequest, $0.Credential>(
'Update',
update_Pre,
false,
false,
($core.List<$core.int> value) => $0.UpdateRequest.fromBuffer(value),
($0.Credential value) => value.writeToBuffer()));
$addMethod($grpc.ServiceMethod<$0.IdRequest, $0.DeleteResponse>(
'Delete',
delete_Pre,
false,
false,
($core.List<$core.int> value) => $0.IdRequest.fromBuffer(value),
($0.DeleteResponse value) => value.writeToBuffer()));
}
$async.Stream<$0.Metadata> getAllMetadata_Pre(
$grpc.ServiceCall call, $async.Future request) async* {
yield* getAllMetadata(call, (await request) as $0.GetAllMetadataRequest);
}
$async.Future<$0.Credential> get_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return get(call, await request);
}
$async.Future<$0.Credential> create_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return create(call, await request);
}
$async.Future<$0.Credential> update_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return update(call, await request);
}
$async.Future<$0.DeleteResponse> delete_Pre(
$grpc.ServiceCall call, $async.Future request) async {
return delete(call, await request);
}
$async.Stream<$0.Metadata> getAllMetadata(
$grpc.ServiceCall call, $0.GetAllMetadataRequest request);
$async.Future<$0.Credential> get(
$grpc.ServiceCall call, $0.IdRequest request);
$async.Future<$0.Credential> create(
$grpc.ServiceCall call, $0.CredentialRequest request);
$async.Future<$0.Credential> update(
$grpc.ServiceCall call, $0.UpdateRequest request);
$async.Future<$0.DeleteResponse> delete(
$grpc.ServiceCall call, $0.IdRequest request);
}

View File

@ -0,0 +1,124 @@
///
// Generated code. Do not modify.
// source: service.proto
///
// ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name
const DeleteResponse$json = const {
'1': 'DeleteResponse',
'2': const [
const {'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'},
],
};
const GetAllMetadataRequest$json = const {
'1': 'GetAllMetadataRequest',
'2': const [
const {'1': 'source_host', '3': 1, '4': 1, '5': 9, '10': 'sourceHost'},
],
};
const IdRequest$json = const {
'1': 'IdRequest',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
],
};
const UpdateRequest$json = const {
'1': 'UpdateRequest',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {
'1': 'credential',
'3': 2,
'4': 1,
'5': 11,
'6': '.selfpass.credentials.CredentialRequest',
'10': 'credential'
},
],
};
const DumpResponse$json = const {
'1': 'DumpResponse',
'2': const [
const {'1': 'contents', '3': 1, '4': 1, '5': 12, '10': 'contents'},
],
};
const EmptyRequest$json = const {
'1': 'EmptyRequest',
};
const Metadata$json = const {
'1': 'Metadata',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {
'1': 'created_at',
'3': 2,
'4': 1,
'5': 11,
'6': '.google.protobuf.Timestamp',
'10': 'createdAt'
},
const {
'1': 'updated_at',
'3': 3,
'4': 1,
'5': 11,
'6': '.google.protobuf.Timestamp',
'10': 'updatedAt'
},
const {'1': 'primary', '3': 4, '4': 1, '5': 9, '10': 'primary'},
const {'1': 'source_host', '3': 5, '4': 1, '5': 9, '10': 'sourceHost'},
const {'1': 'login_url', '3': 6, '4': 1, '5': 9, '10': 'loginUrl'},
const {'1': 'tag', '3': 7, '4': 1, '5': 9, '10': 'tag'},
],
};
const Credential$json = const {
'1': 'Credential',
'2': const [
const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
const {
'1': 'created_at',
'3': 2,
'4': 1,
'5': 11,
'6': '.google.protobuf.Timestamp',
'10': 'createdAt'
},
const {
'1': 'updated_at',
'3': 3,
'4': 1,
'5': 11,
'6': '.google.protobuf.Timestamp',
'10': 'updatedAt'
},
const {'1': 'primary', '3': 4, '4': 1, '5': 9, '10': 'primary'},
const {'1': 'username', '3': 5, '4': 1, '5': 9, '10': 'username'},
const {'1': 'email', '3': 6, '4': 1, '5': 9, '10': 'email'},
const {'1': 'password', '3': 7, '4': 1, '5': 9, '10': 'password'},
const {'1': 'source_host', '3': 8, '4': 1, '5': 9, '10': 'sourceHost'},
const {'1': 'login_url', '3': 9, '4': 1, '5': 9, '10': 'loginUrl'},
const {'1': 'tag', '3': 10, '4': 1, '5': 9, '10': 'tag'},
const {'1': 'otp_secret', '3': 11, '4': 1, '5': 9, '10': 'otpSecret'},
],
};
const CredentialRequest$json = const {
'1': 'CredentialRequest',
'2': const [
const {'1': 'primary', '3': 1, '4': 1, '5': 9, '10': 'primary'},
const {'1': 'username', '3': 2, '4': 1, '5': 9, '10': 'username'},
const {'1': 'email', '3': 3, '4': 1, '5': 9, '10': 'email'},
const {'1': 'password', '3': 4, '4': 1, '5': 9, '10': 'password'},
const {'1': 'source_host', '3': 5, '4': 1, '5': 9, '10': 'sourceHost'},
const {'1': 'login_url', '3': 6, '4': 1, '5': 9, '10': 'loginUrl'},
const {'1': 'tag', '3': 7, '4': 1, '5': 9, '10': 'tag'},
const {'1': 'otp_secret', '3': 8, '4': 1, '5': 9, '10': 'otpSecret'},
],
};

View File

@ -0,0 +1,75 @@
syntax = "proto3";
package selfpass.credentials;
option go_package = "protobuf";
import "google/protobuf/timestamp.proto";
service CredentialService {
rpc GetAllMetadata (GetAllMetadataRequest) returns (stream Metadata);
rpc Get (IdRequest) returns (Credential);
rpc Create (CredentialRequest) returns (Credential);
rpc Update (UpdateRequest) returns (Credential);
rpc Delete (IdRequest) returns (DeleteResponse);
// rpc Dump (EmptyRequest) returns (DumpResponse);
}
message DeleteResponse {
bool success = 1;
}
message GetAllMetadataRequest {
string source_host = 1;
}
message IdRequest {
string id = 1;
}
message UpdateRequest {
string id = 1;
CredentialRequest credential = 2;
}
message DumpResponse {
bytes contents = 1;
}
message EmptyRequest {
}
message Metadata {
string id = 1;
google.protobuf.Timestamp created_at = 2;
google.protobuf.Timestamp updated_at = 3;
string primary = 4;
string source_host = 5;
string login_url = 6;
string tag = 7;
}
message Credential {
string id = 1;
google.protobuf.Timestamp created_at = 2;
google.protobuf.Timestamp updated_at = 3;
string primary = 4;
string username = 5;
string email = 6;
string password = 7;
string source_host = 8;
string login_url = 9;
string tag = 10;
string otp_secret = 11;
}
message CredentialRequest {
string primary = 1;
string username = 2;
string email = 3;
string password = 4;
string source_host = 5;
string login_url = 6;
string tag = 7;
string otp_secret = 8;
}

View File

@ -0,0 +1,83 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:grpc/grpc.dart';
import '../protobuf/service.pbgrpc.dart' as grpc;
import '../protobuf/service.pb.dart' as protobuf;
import '../types/abstracts.dart';
import '../types/connection_config.dart';
import '../types/credential.dart';
class GRPCCredentialsClient implements CredentialsRepo {
static GRPCCredentialsClient _cached;
grpc.CredentialServiceClient _client;
GRPCCredentialsClient(ConnectionConfig config) {
final caCert = utf8.encode(config.caCertificate);
final cert = utf8.encode(config.certificate);
final privateCert = utf8.encode(config.privateCertificate);
final splitHost = config.host.split(':');
final hostname = splitHost[0];
final port = int.parse(splitHost[1]);
_client = grpc.CredentialServiceClient(ClientChannel(
hostname,
port: port,
options: ChannelOptions(
credentials: _ChannelCredentials(caCert, cert, privateCert),
),
));
}
factory GRPCCredentialsClient.cached({ConnectionConfig config}) =>
config == null ? _cached : _cached = GRPCCredentialsClient(config);
Stream<Metadata> getAllMetadata(String sourceHost) {
final request = grpc.GetAllMetadataRequest();
request.sourceHost = sourceHost;
return _client.getAllMetadata(request).map<Metadata>(
(protobuf.Metadata pbMetadata) => Metadata.fromProtobuf(pbMetadata));
}
Future<Credential> get(String id) async {
final request = grpc.IdRequest();
request.id = id;
return Credential.fromProtobuf(await _client.get(request));
}
Future<Credential> create(CredentialInput input) async {
return Credential();
}
Future<Credential> update(String id, CredentialInput input) async {
return Credential();
}
Future<void> delete(String id) {
final request = grpc.IdRequest();
request.id = id;
return _client.delete(request);
}
}
class _ChannelCredentials extends ChannelCredentials {
final List<int> _key;
final List<int> _cert;
const _ChannelCredentials(List<int> caCert, this._cert, this._key)
: super.secure(certificates: caCert);
@override
SecurityContext get securityContext {
return super.securityContext
..usePrivateKeyBytes(_key)
..useCertificateChainBytes(_cert);
}
}

View File

@ -0,0 +1,91 @@
import 'dart:convert';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../types/abstracts.dart';
import '../types/connection_config.dart';
import '../utils/crypto.dart' as crypto;
class SecureStorageConfig implements ConfigRepo {
static const _keyPrivateKey = "private_key";
static const _keyConnectionConfig = "connection_config";
static const _keyPassword = "password";
final _storage = FlutterSecureStorage();
bool _passwordMatched = false;
String _password;
String get password {
_checkIfPasswordMatched();
return _password;
}
Future<void> setPrivateKey(String key) {
_checkIfPasswordMatched();
return _storage.write(key: _keyPrivateKey, value: key.replaceAll('-', ''));
}
Future<String> get privateKey {
_checkIfPasswordMatched();
return _storage.read(key: _keyPrivateKey);
}
Future<void> setPassword(String password) {
_checkIfPasswordMatched();
_password = password;
return _storage.write(
key: _keyPassword, value: crypto.hashPassword(password));
}
Future<bool> get passwordIsSet async {
final passHash = await _storage.read(key: _keyPassword);
if (passHash != null) {
return true;
}
_passwordMatched = true;
return false;
}
Future<bool> matchesPasswordHash(String password) async {
_passwordMatched = crypto.matchHashedPassword(
await _storage.read(key: _keyPassword), password);
if (_passwordMatched) _password = password;
return _passwordMatched;
}
Future<void> setConnectionConfig(ConnectionConfig config) {
_checkIfPasswordMatched();
return _storage.write(
key: _keyConnectionConfig, value: json.encode(config));
}
Future<ConnectionConfig> get connectionConfig async {
_checkIfPasswordMatched();
final connConfig = await _storage.read(key: _keyConnectionConfig);
if (connConfig == null) {
return null;
}
return ConnectionConfig.fromJson(json.decode(connConfig));
}
Future<void> deleteAll() {
_checkIfPasswordMatched();
return _storage.deleteAll();
}
void _checkIfPasswordMatched() {
if (_passwordMatched) return;
throw Exception('password not matched yet');
}
}

View File

@ -0,0 +1,129 @@
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import '../types/abstracts.dart';
import '../widgets/text_field.dart';
class Authentication extends StatefulWidget {
@override
_AuthenticationState createState() => _AuthenticationState();
}
class _AuthenticationState extends State<Authentication> {
final TextEditingController _passwordController = TextEditingController();
final TextEditingController _confirmController = TextEditingController();
bool _invalid = false;
bool _passesDontMatch = false;
ConfigRepo _config;
Future<bool> _passwordIsSet;
@override
didChangeDependencies() {
super.didChangeDependencies();
_config = Provider.of<ConfigRepo>(context);
_passwordIsSet = _config.passwordIsSet;
}
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 50.0),
child: FutureBuilder<bool>(
future: _passwordIsSet,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) =>
snapshot.connectionState == ConnectionState.done
? Column(
children: _buildColumnChildren(context, snapshot.data))
: Center(child: CupertinoActivityIndicator()),
),
),
);
}
List<Widget> _buildColumnChildren(BuildContext context, bool passwordIsSet) {
List<Widget> children = [
const Spacer(flex: 4),
const Flexible(child: Text('Master password:')),
Flexible(
child: TextField(
maxLines: 1,
obscure: true,
autofocus: true,
controller: _passwordController,
),
),
];
if (!passwordIsSet) {
children.add(const Flexible(child: Text('Re-enter password:')));
children.add(Flexible(
child: TextField(
maxLines: 1,
obscure: true,
controller: _confirmController,
),
));
}
if (_invalid) {
children.add(const Flexible(
child: Text(
'invalid masterpass',
style: TextStyle(color: CupertinoColors.destructiveRed),
),
));
}
if (_passesDontMatch) {
children.add(const Flexible(
child: Text(
'passwords don\'t match',
style: TextStyle(color: CupertinoColors.destructiveRed),
),
));
}
children.add(CupertinoButton(
child: Text('Enter'),
onPressed: _buildEnterPressedBuilder(context),
));
if (_passesDontMatch) {
children.add(const Spacer(flex: 1));
} else if (_invalid || !passwordIsSet) {
children.add(const Spacer(flex: 2));
} else {
children.add(const Spacer(flex: 3));
}
return children;
}
VoidCallback _buildEnterPressedBuilder(BuildContext context) {
return () async {
if (await _passwordIsSet) {
if (await _config.matchesPasswordHash(_passwordController.text)) {
Navigator.of(context).pushReplacementNamed('/home',
arguments: await _config.connectionConfig);
return;
}
this.setState(() => _invalid = true);
return;
}
if (_passwordController.text != _confirmController.text) {
this.setState(() {
_passesDontMatch = true;
});
return;
}
_config.setPassword(_passwordController.text);
_passwordIsSet = Future<bool>.value(true);
Navigator.of(context).pushReplacementNamed('/config');
};
}
}

View File

@ -0,0 +1,135 @@
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import '../types/abstracts.dart';
import '../types/connection_config.dart';
import '../widgets/text_field.dart';
class Config extends StatefulWidget {
final ConnectionConfig connectionConfig;
final String privateKey;
const Config(this.connectionConfig, this.privateKey, {Key key})
: super(key: key);
@override
State createState() => _ConfigState(this.connectionConfig, this.privateKey);
}
class _ConfigState extends State<Config> {
TextEditingController _hostController;
TextEditingController _caCertController;
TextEditingController _certController;
TextEditingController _privateCertController;
TextEditingController _privateKeyController;
ConnectionConfig _connectionConfig;
String _privateKey;
ConfigRepo _config;
_ConfigState(this._connectionConfig, this._privateKey) {
if (_connectionConfig == null) {
_connectionConfig = ConnectionConfig();
}
_hostController = TextEditingController(text: _connectionConfig.host);
_certController =
TextEditingController(text: _connectionConfig.certificate);
_caCertController =
TextEditingController(text: _connectionConfig.caCertificate);
_privateCertController =
TextEditingController(text: _connectionConfig.privateCertificate);
_privateKeyController = TextEditingController(text: _privateKey);
}
@override
didChangeDependencies() async {
super.didChangeDependencies();
_config = Provider.of<ConfigRepo>(context);
}
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: _connectionConfig.host == null
? null
: CupertinoNavigationBar(
trailing: GestureDetector(
onTap: _buildResetAllHandler(context),
child: Text('Reset App',
style: TextStyle(color: CupertinoColors.destructiveRed)),
),
),
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 30),
child: ListView(children: [
Container(margin: EdgeInsets.only(top: 10), child: Text('Host:')),
TextField(maxLines: 1, controller: _hostController),
Container(
margin: EdgeInsets.only(top: 5), child: Text('Private key:')),
TextField(maxLines: 1, controller: _privateKeyController),
Container(
margin: EdgeInsets.only(top: 5), child: Text('CA certificate:')),
TextField(maxLines: 5, controller: _caCertController),
Container(
margin: EdgeInsets.only(top: 5),
child: Text('Client certificate:')),
TextField(maxLines: 5, controller: _certController),
Container(
margin: EdgeInsets.only(top: 5),
child: Text('Private certificate:')),
TextField(maxLines: 5, controller: _privateCertController),
CupertinoButton(
child: Text('Save'), onPressed: _makeSaveOnPressed(context)),
]),
),
);
}
GestureTapCallback _buildResetAllHandler(BuildContext context) {
return () {
showCupertinoDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
content: Text('Are you sure?'),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
child: Text('Cancel'),
onPressed: () => Navigator.of(context).pop(),
),
CupertinoDialogAction(
isDestructiveAction: true,
child: Text('Confirm'),
onPressed: () async {
_connectionConfig = null;
await _config.deleteAll();
Navigator.of(context)
.pushNamedAndRemoveUntil('/', ModalRoute.withName('/'));
},
),
],
),
);
};
}
VoidCallback _makeSaveOnPressed(BuildContext context) {
return () async {
final connConfig = ConnectionConfig(
host: _hostController.text,
certificate: _certController.text,
caCertificate: _caCertController.text,
privateCertificate: _privateCertController.text,
);
await _config.setConnectionConfig(connConfig);
await _config.setPrivateKey(_privateKeyController.text);
Navigator.of(context)
.pushReplacementNamed('/home', arguments: connConfig);
};
}
}

View File

@ -0,0 +1,177 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:otp/otp.dart';
import '../types/credential.dart' as types;
import '../widgets/text_field.dart';
class Credential extends StatefulWidget {
final types.Credential credential;
const Credential(this.credential, {Key key}) : super(key: key);
@override
State createState() => _CredentialState(credential);
}
class _CredentialState extends State<Credential> {
_CredentialControllers _controllers;
Map<String, _FieldBuildConfig> _fieldMap;
types.Credential _credential;
_CredentialState(this._credential) : super();
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(),
child: Container(
padding: const EdgeInsets.only(top: 15, bottom: 30, left: 30),
child: ListView(
children: _buildFieldRows(context),
),
),
);
}
Map<String, _FieldBuildConfig> _buildFieldMap(
_CredentialControllers controllers,
types.Credential credential,
) {
final fieldMap = {
'Id:': _FieldBuildConfig(mutable: false, text: credential.meta.id),
'Created:': _FieldBuildConfig(
mutable: false,
copyable: false,
text: credential.meta.createdAt.toString(),
),
'Updated:': _FieldBuildConfig(
mutable: false,
copyable: false,
text: credential.meta.updatedAt.toString(),
),
'Host:': _FieldBuildConfig(controller: controllers.sourceHost),
'Primary:': _FieldBuildConfig(controller: controllers.primary),
};
if (credential.meta.tag != null && credential.meta.tag != '') {
fieldMap['Tag'] = _FieldBuildConfig(controller: controllers.tag);
}
if (credential.username != null && credential.username != '') {
fieldMap['User:'] = _FieldBuildConfig(controller: controllers.username);
}
if (credential.email != null && credential.email != '') {
fieldMap['Email:'] = _FieldBuildConfig(controller: controllers.email);
}
fieldMap['Password:'] =
_FieldBuildConfig(controller: controllers.password, obscured: true);
if (credential.otpSecret != null && credential.otpSecret != '') {
fieldMap['OTP Secret:'] = _FieldBuildConfig(
controller: controllers.otpSecret, obscured: true, otp: true);
}
return fieldMap;
}
List<Widget> _buildFieldRows(BuildContext context) {
List<Widget> rows = [];
_controllers = _CredentialControllers.fromCredential(_credential);
_fieldMap = _buildFieldMap(_controllers, _credential);
_fieldMap.forEach((key, value) {
rows.add(Container(
margin: EdgeInsets.only(top: 2.5),
child: Text(key, style: TextStyle(fontWeight: FontWeight.w600)),
));
final List<Widget> widgets = [
Expanded(
flex: 3,
child: value.mutable
? TextField(
maxLines: 1,
controller: value.controller,
obscure: value.obscured)
: Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Text(value.text)),
),
];
if (value.copyable) {
widgets.add(Expanded(
child: CupertinoButton(
child: Text(value.otp ? 'OTP' : 'Copy'),
onPressed: () => Clipboard.setData(ClipboardData(
text: value.otp
? OTP
.generateTOTPCode(value.controller.text,
DateTime.now().millisecondsSinceEpoch)
.toString()
: value.mutable ? value.controller.text : value.text,
)),
),
));
}
rows.add(Row(children: widgets));
});
return rows;
}
}
class _FieldBuildConfig {
final TextEditingController controller;
final String text;
final bool mutable;
final bool copyable;
final bool obscured;
final bool otp;
const _FieldBuildConfig({
this.mutable = true,
this.copyable = true,
this.obscured = false,
this.otp = false,
this.controller,
this.text,
});
}
class _CredentialControllers {
final TextEditingController sourceHost;
final TextEditingController primary;
final TextEditingController tag;
final TextEditingController username;
final TextEditingController email;
final TextEditingController password;
final TextEditingController otpSecret;
const _CredentialControllers({
this.sourceHost,
this.primary,
this.tag,
this.username,
this.email,
this.password,
this.otpSecret,
});
factory _CredentialControllers.fromCredential(types.Credential credential) =>
_CredentialControllers(
sourceHost: TextEditingController(text: credential.meta.sourceHost),
primary: TextEditingController(text: credential.meta.primary),
tag: TextEditingController(text: credential.meta.tag),
username: TextEditingController(text: credential.username),
email: TextEditingController(text: credential.email),
password: TextEditingController(text: credential.password),
otpSecret: TextEditingController(text: credential.otpSecret),
);
}

View File

@ -0,0 +1,72 @@
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import '../types/abstracts.dart';
import '../types/credential.dart';
import '../utils/crypto.dart' as crypto;
import '../widgets/tappable_text_list.dart';
class Credentials extends StatelessWidget {
final List<Metadata> metadatas;
const Credentials(this.metadatas);
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: TappableTextList(tappableText: _buildTappableText(context)),
navigationBar: CupertinoNavigationBar(),
);
}
Map<String, GestureTapCallback> _buildTappableText(BuildContext context) {
final makeOnTapHandler = (String id) => () async {
showCupertinoDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
content: Column(
children: [
Text('Decrypting credential...'),
Container(
margin: EdgeInsets.only(top: 10),
child: CupertinoActivityIndicator()),
],
)),
);
final config = Provider.of<ConfigRepo>(context);
final client = Provider.of<CredentialsRepo>(context);
final Future<String> privateKey = config.privateKey;
final String password = config.password;
final credential = await client.get(id);
credential.password = crypto.decryptPassword(
password, await privateKey, credential.password);
if (credential.otpSecret != null && credential.otpSecret != '') {
credential.otpSecret = crypto.decryptPassword(
password, await privateKey, credential.otpSecret);
}
Navigator.of(context)
..pop()
..pushNamed('/credential', arguments: credential);
};
Map<String, GestureTapCallback> tappableText = {};
metadatas.forEach((Metadata metadata) {
var primary = metadata.primary;
if (metadata.tag != null && metadata.tag != '') {
primary += "-" + metadata.tag;
}
tappableText[primary] = makeOnTapHandler(metadata.id);
});
return tappableText;
}
}

View File

@ -0,0 +1,139 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import '../types/abstracts.dart';
import '../types/credential.dart';
import '../types/screen_arguments.dart';
import '../widgets/tappable_text_list.dart';
class Home extends StatefulWidget {
const Home({Key key}) : super(key: key);
@override
State createState() => _HomeState();
}
class _HomeState extends State<Home> with WidgetsBindingObserver {
CredentialsRepo _client;
ConfigRepo _config;
Future<List<Metadata>> _metadatas;
bool _stateIsPaused = false;
Timer _pausedStateTimer;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_config = Provider.of<ConfigRepo>(context);
_client = Provider.of<CredentialsRepo>(context);
_metadatas = _client.getAllMetadata('').toList();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
_stateIsPaused = state == AppLifecycleState.paused;
if (_stateIsPaused) {
_pausedStateTimer = _newPausedStateTimer();
return;
}
if (_pausedStateTimer != null) _pausedStateTimer.cancel();
}
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: FutureBuilder<List<Metadata>>(
future: _metadatas,
builder: (
BuildContext context,
AsyncSnapshot<List<Metadata>> snapshot,
) =>
(snapshot.connectionState == ConnectionState.done)
? TappableTextList(
tappableText: _buildTappableText(context, snapshot.data))
: Center(child: CupertinoActivityIndicator()),
),
navigationBar: CupertinoNavigationBar(
leading: GestureDetector(
child: Align(
child: Text('Lock',
style: TextStyle(color: CupertinoColors.destructiveRed)),
alignment: Alignment(-0.9, 0)),
onTap: _makeLockOnTapHandler(context),
),
trailing: GestureDetector(
child: Icon(CupertinoIcons.gear),
onTap: _makeConfigOnTapHandler(context),
),
),
);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
if (_pausedStateTimer != null) _pausedStateTimer.cancel();
super.dispose();
}
Timer _newPausedStateTimer() {
const checkPeriod = 30;
return Timer(Duration(seconds: checkPeriod), () {
Navigator.of(context)
.pushNamedAndRemoveUntil('/', ModalRoute.withName('/home'));
});
}
Map<String, GestureTapCallback> _buildTappableText(
BuildContext context,
List<Metadata> metadatas,
) {
final Map<String, List<Metadata>> metaMap = {};
metadatas.sort((a, b) => a.id.compareTo(b.id));
for (var metadata in metadatas) {
final source = metadata.sourceHost;
if (metaMap[source] == null) {
metaMap[source] = [metadata];
} else {
metaMap[source].add(metadata);
}
}
final handleOnTap = (List<Metadata> metadatas) => () async =>
Navigator.of(context).pushNamed('/credentials', arguments: metadatas);
final Map<String, GestureTapCallback> tappableText = {};
metaMap.forEach((String key, List<Metadata> value) =>
tappableText[key] = handleOnTap(value));
return tappableText;
}
GestureTapCallback _makeLockOnTapHandler(BuildContext context) {
return () => Navigator.of(context).pushReplacementNamed('/');
}
GestureTapCallback _makeConfigOnTapHandler(BuildContext context) {
return () async => Navigator.of(context).pushNamed('/config',
arguments: ConfigScreenArguments(
connectionConfig: await _config.connectionConfig,
privateKey: await _config.privateKey));
}
}

View File

@ -0,0 +1,27 @@
import 'dart:async';
import 'credential.dart';
import 'connection_config.dart';
abstract class CredentialsRepo {
Stream<Metadata> getAllMetadata(String sourceHost);
Future<Credential> get(String id);
Future<Credential> create(CredentialInput input);
Future<Credential> update(String id, CredentialInput input);
Future<void> delete(String id);
}
abstract class ConfigRepo {
Future<void> setPrivateKey(String key);
Future<String> get privateKey;
String get password;
Future<void> setPassword(String password);
Future<bool> get passwordIsSet;
Future<bool> matchesPasswordHash(String password);
Future<void> setConnectionConfig(ConnectionConfig config);
Future<ConnectionConfig> get connectionConfig;
Future<void> deleteAll();
}

View File

@ -0,0 +1,27 @@
class ConnectionConfig {
String host;
String caCertificate;
String certificate;
String privateCertificate;
ConnectionConfig({
this.host,
this.caCertificate,
this.certificate,
this.privateCertificate,
});
ConnectionConfig.fromJson(Map<String, dynamic> json) {
host = json['host'];
caCertificate = json['caCertificate'];
certificate = json['certificate'];
privateCertificate = json['privateCertificate'];
}
Map<String, dynamic> toJson() => {
'host': host,
'caCertificate': caCertificate,
'certificate': certificate,
'privateCertificate': privateCertificate,
};
}

View File

@ -0,0 +1,94 @@
import '../protobuf/service.pb.dart' as protobuf;
class Metadata {
String id;
String sourceHost;
DateTime createdAt;
DateTime updatedAt;
String primary;
String loginUrl;
String tag;
Metadata({
this.id,
this.sourceHost,
this.createdAt,
this.updatedAt,
this.primary,
this.loginUrl,
this.tag,
});
Metadata.fromProtobuf(protobuf.Metadata metadata) {
id = metadata.id;
createdAt = metadata.createdAt.toDateTime();
updatedAt = metadata.updatedAt.toDateTime();
sourceHost = metadata.sourceHost;
primary = metadata.primary;
loginUrl = metadata.loginUrl;
tag = metadata.tag;
}
@override
String toString() => "id: $id";
}
class MetadataInput {
String sourceHost;
String primary;
String loginUrl;
String tag;
MetadataInput({this.sourceHost, this.primary, this.loginUrl, this.tag});
}
class Credential {
Metadata meta;
String username;
String email;
String password;
String otpSecret;
Credential({
this.meta,
this.username,
this.email,
this.password,
this.otpSecret,
});
Credential.fromProtobuf(protobuf.Credential credential) {
meta = Metadata(
id: credential.id,
createdAt: credential.createdAt.toDateTime(),
updatedAt: credential.updatedAt.toDateTime(),
sourceHost: credential.sourceHost,
primary: credential.primary,
loginUrl: credential.loginUrl,
tag: credential.tag,
);
username = credential.username;
email = credential.email;
password = credential.password;
otpSecret = credential.otpSecret;
}
@override
String toString() => "meta: $meta\n";
}
class CredentialInput {
MetadataInput meta;
String username;
String email;
String password;
String otpSecret;
CredentialInput({
this.meta,
this.username,
this.email,
this.password,
this.otpSecret,
});
}

View File

@ -0,0 +1,8 @@
import 'connection_config.dart';
class ConfigScreenArguments {
final ConnectionConfig connectionConfig;
final String privateKey;
const ConfigScreenArguments({this.connectionConfig, this.privateKey});
}

View File

@ -0,0 +1,42 @@
import 'dart:math';
import 'dart:convert';
import 'dart:typed_data';
import 'package:crypt/crypt.dart';
import 'package:encrypt/encrypt.dart';
import 'package:password_hash/password_hash.dart';
String hashPassword(String password) {
const saltSize = 16;
const saltIntMax = 256;
final random = Random.secure();
final saltInts =
List<int>.generate(saltSize, (_) => random.nextInt(saltIntMax));
final salt = base64.encode(saltInts);
return Crypt.sha256(password, salt: salt).toString();
}
bool matchHashedPassword(String hashedPassword, String password) =>
Crypt(hashedPassword).match(password);
String decryptPassword(String masterpass, privateKey, ciphertext) {
final key =
PBKDF2().generateKey(masterpass, privateKey, pbkdf2Rounds, keySize);
var cipherbytes = base64.decode(ciphertext);
final iv =
IV(Uint8List.fromList(cipherbytes.getRange(0, aesBlockSize).toList()));
cipherbytes = Uint8List.fromList(
cipherbytes.getRange(aesBlockSize, cipherbytes.length).toList());
final encrypter = Encrypter(AES(Key(key), mode: AESMode.cbc));
return encrypter.decrypt(Encrypted(cipherbytes), iv: iv);
}
const pbkdf2Rounds = 4096;
const keySize = 32;
const aesBlockSize = 16;

View File

@ -0,0 +1,35 @@
import 'package:flutter/cupertino.dart';
class TappableTextList extends StatelessWidget {
final Map<String, GestureTapCallback> tappableText;
TappableTextList({Key key, this.tappableText}) : super(key: key);
@override
Widget build(BuildContext context) {
return ListView(
children: _buildListChildren(context),
);
}
List<Widget> _buildListChildren(BuildContext context) {
List<Widget> widgets = [];
tappableText.forEach((String text, GestureTapCallback handleOnTap) {
widgets.add(GestureDetector(
onTap: handleOnTap,
child: Container(
padding: const EdgeInsets.symmetric(vertical: 15.0),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(color: CupertinoColors.lightBackgroundGray),
),
),
child: Text(text, textAlign: TextAlign.center),
),
));
});
return widgets;
}
}

View File

@ -0,0 +1,57 @@
import 'package:flutter/cupertino.dart';
typedef OnSubmittedBuilder = ValueChanged<String> Function(
BuildContext context,
);
class TextField extends StatelessWidget {
final OnSubmittedBuilder onSubmittedBuilder;
final TextEditingController controller;
final OverlayVisibilityMode clearButtonMode;
final Widget prefix;
final Widget suffix;
final bool obscure;
final bool autofocus;
final bool autocorrect;
final int minLines;
final int maxLines;
const TextField({
this.onSubmittedBuilder,
this.controller,
this.obscure = false,
this.autofocus = false,
this.minLines,
this.maxLines,
this.autocorrect = false,
this.prefix,
this.suffix,
this.clearButtonMode = OverlayVisibilityMode.editing,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: CupertinoTextField(
decoration: BoxDecoration(
border: Border.all(color: CupertinoColors.black),
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
),
clearButtonMode: clearButtonMode,
textAlign: TextAlign.start,
onSubmitted: this.onSubmittedBuilder != null
? onSubmittedBuilder(context)
: null,
controller: controller,
obscureText: obscure,
autofocus: autofocus,
autocorrect: autocorrect,
minLines: minLines,
maxLines: maxLines,
prefix: prefix,
suffix: suffix,
),
);
}
}

279
client/pubspec.lock Normal file
View File

@ -0,0 +1,279 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.2"
asn1lib:
dependency: transitive
description:
name: asn1lib
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.8"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
base32:
dependency: transitive
description:
name: base32
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.2"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.11"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
crypt:
dependency: "direct main"
description:
name: crypt
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.7"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
encrypt:
dependency: "direct main"
description:
name: encrypt
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.dartlang.org"
source: hosted
version: "0.10.9"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_secure_storage:
dependency: "direct main"
description:
name: flutter_secure_storage
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.1+1"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
googleapis_auth:
dependency: transitive
description:
name: googleapis_auth
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.8"
grpc:
dependency: "direct main"
description:
name: grpc
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0+2"
http2:
dependency: transitive
description:
name: http2
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.3"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
otp:
dependency: "direct main"
description:
name: otp
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
password_hash:
dependency: "direct main"
description:
name: password_hash
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.2"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
pointycastle:
dependency: transitive
description:
name: pointycastle
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
protobuf:
dependency: "direct main"
description:
name: protobuf
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.12"
provider:
dependency: "direct main"
description:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0+1"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.3"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.5"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.5"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.6"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
sdks:
dart: ">=2.2.2 <3.0.0"

45
client/pubspec.yaml Normal file
View File

@ -0,0 +1,45 @@
name: selfpass_client
description: The cross-platform Selfpass client.
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 0.1.0
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
grpc: ^1.0.3
protobuf: ^0.13.12
provider: ^3.0.0
crypt: ^1.0.7
flutter_secure_storage: ^3.2.1
password_hash: ^2.0.0
encrypt: ^3.2.0
otp: ^1.0.3
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:

View File

@ -0,0 +1,30 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:selfpass_client/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(Selfpass());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}