...
 
Commits (5)
......@@ -6,7 +6,7 @@
import Foundation
class MPSite: NSObject, Comparable {
var observers = Observers<MPSiteObserver>()
let observers = Observers<MPSiteObserver>()
let user: MPUser
let siteName: String
......@@ -58,7 +58,7 @@ class MPSite: NSObject, Comparable {
self.observers.notify { $0.siteDidChange() }
}
}
var color: UIColor {
var color: UIColor? {
didSet {
self.observers.notify { $0.siteDidChange() }
}
......@@ -85,7 +85,7 @@ class MPSite: NSObject, Comparable {
self.url = url
self.uses = uses
self.lastUsed = lastUsed ?? Date()
self.color = MPUtils.color( message: self.siteName )
self.color = self.siteName.color()
super.init()
MPURLUtils.preview( url: self.siteName, imageResult: { image in
......
......@@ -6,7 +6,7 @@
import Foundation
class MPUser {
var observers = Observers<MPUserObserver>()
let observers = Observers<MPUserObserver>()
let fullName: String
var avatar: MPUserAvatar {
......
//
// Created by Maarten Billemont on 2018-09-22.
// Created by Maarten Billemont on 2018-10-15.
// Copyright (c) 2018 Lyndir. All rights reserved.
//
import Foundation
class MPSiteDetailsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, MPSiteObserver {
var site: MPSite? {
willSet {
self.site?.observers.unregister( self )
}
didSet {
if let site = self.site {
site.observers.register( self ).siteDidChange()
}
}
}
class MPSiteDetailViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, MPSiteObserver {
let observers = Observers<MPSiteDetailObserver>()
let site: MPSite
let closeButton = MPButton( title: "╳" )
let headingImageView = MPImageView( image: UIImage( named: "icon_sliders" ) )
let headingLabel = UILabel()
let contentView = UIView()
let tableView = UITableView( frame: .zero, style: .plain )
let closeButton = MPButton.closeButton()
let tableView = UITableView( frame: .zero, style: .plain )
let items = [ Item( title: "Counter", valueProvider: { "\($0.counter.rawValue)" } ),
Item( title: "Password Type", valueProvider: { String( cString: mpw_longNameForType( $0.resultType ) ) } ),
Item( title: "Login Type", valueProvider: { String( cString: mpw_longNameForType( $0.loginType ) ) } ),
Item( title: "Algorithm", valueProvider: { "V\($0.algorithm.rawValue)" } ),
Item( title: "URL", valueProvider: { $0.url } ),
Item( title: "Last Used", valueProvider: { $0.lastUsed.format() } ),
Item( title: "Total Uses", valueProvider: { "\($0.uses)" } ) ]
// MARK: - Life
......@@ -30,80 +26,46 @@ class MPSiteDetailsViewController: UIViewController, UITableViewDelegate, UITabl
}
init(site: MPSite) {
self.site = site
super.init( nibName: nil, bundle: nil )
self.modalPresentationStyle = .overCurrentContext
defer {
self.site = site
}
site.observers.register( self ).siteDidChange()
}
override func viewDidLoad() {
// - View
self.view.backgroundColor = .black
self.contentView.backgroundColor = UIColor( white: 0.9, alpha: 1 )
self.closeButton.button.addTarget( self, action: #selector( close ), for: .touchUpInside )
self.headingImageView.preservesImageRatio = true
self.headingLabel.textColor = .white
self.headingLabel.shadowColor = .black
if #available( iOS 11.0, * ) {
self.headingLabel.font = UIFont.preferredFont( forTextStyle: .largeTitle )
}
else {
self.headingLabel.font = UIFont.preferredFont( forTextStyle: .title1 )
}
self.headingLabel.font = UIFont.preferredFont( forTextStyle: .headline )
self.tableView.delegate = self
self.tableView.dataSource = self
self.tableView.separatorStyle = .none
self.tableView.layer.cornerRadius = 8
self.tableView.registerCell( Cell.self )
let tableViewEffect = UIView( containing: self.tableView, withLayoutMargins: .zero )!
tableViewEffect.layer.shadowRadius = 8
tableViewEffect.layer.shadowOpacity = 0.382
// - Hierarchy
self.view.addSubview( self.contentView )
self.view.addSubview( tableViewEffect )
self.view.addSubview( self.closeButton )
self.contentView.addSubview( self.headingImageView )
self.contentView.addSubview( self.headingLabel )
self.contentView.addSubview( tableViewEffect )
// - Layout
ViewConfiguration( view: self.contentView )
ViewConfiguration( view: tableViewEffect )
.constrainTo { $1.topAnchor.constraint( equalTo: $0.topAnchor ) }
.constrainTo { $1.leadingAnchor.constraint( equalTo: $0.leadingAnchor ) }
.constrainTo { $1.trailingAnchor.constraint( equalTo: $0.trailingAnchor ) }
.constrainTo { $1.bottomAnchor.constraint( equalTo: $0.bottomAnchor ) }
.constrainTo { $1.heightAnchor.constraint( equalTo: $0.heightAnchor, multiplier: 0.618 ) }
.activate()
ViewConfiguration( view: self.headingLabel )
.constrainTo { $1.leadingAnchor.constraint( equalTo: self.tableView.leadingAnchor, constant: 8 ) }
.constrainTo { $1.trailingAnchor.constraint( equalTo: self.tableView.trailingAnchor, constant: -8 ) }
.constrainTo { $1.bottomAnchor.constraint( equalTo: self.tableView.topAnchor, constant: -8 ) }
.activate()
ViewConfiguration( view: self.headingImageView )
.constrainTo { $1.trailingAnchor.constraint( equalTo: self.tableView.trailingAnchor ) }
.constrainTo { $1.bottomAnchor.constraint( equalTo: self.tableView.topAnchor, constant: 20 ) }
.constrainTo { $1.heightAnchor.constraint( equalToConstant: 96 ) }
.activate()
ViewConfiguration( view: tableViewEffect )
.constrainTo { $1.topAnchor.constraint( equalTo: $0.topAnchor, constant: -40 ) }
.constrainTo { $1.leadingAnchor.constraint( equalTo: $0.layoutMarginsGuide.leadingAnchor ) }
.constrainTo { $1.trailingAnchor.constraint( equalTo: $0.layoutMarginsGuide.trailingAnchor ) }
.constrainTo { $1.bottomAnchor.constraint( equalTo: $0.layoutMarginsGuide.bottomAnchor ) }
.activate()
ViewConfiguration( view: self.closeButton )
.constrainTo { $1.topAnchor.constraint( equalTo: $0.layoutMarginsGuide.topAnchor ) }
.constrainTo { $1.trailingAnchor.constraint( equalTo: $0.layoutMarginsGuide.trailingAnchor ) }
.constrainTo { $1.centerXAnchor.constraint( equalTo: tableViewEffect.centerXAnchor ) }
.constrainTo { $1.centerYAnchor.constraint( equalTo: tableViewEffect.bottomAnchor ) }
.activate()
}
@objc
func close() {
self.dismiss( animated: true )
self.observers.notify { $0.siteDetailShouldDismiss() }
}
// MARK: - UITableViewDelegate
......@@ -111,19 +73,73 @@ class MPSiteDetailsViewController: UIViewController, UITableViewDelegate, UITabl
// MARK: - UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
return self.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
fatalError( "tableView(tableView:indexPath:) has not been implemented" )
let cell = Cell.dequeue( from: tableView, indexPath: indexPath ),
item = self.items[indexPath.item]
item.site = self.site
cell.item = item
return cell
}
// MARK: - MPSiteObserver
func siteDidChange() {
PearlMainQueue {
self.headingLabel.text = self.site?.siteName
self.view.backgroundColor = self.site?.color
for cell in self.tableView.visibleCells {
if let cell = cell as? Cell {
cell.item?.site = self.site
}
}
}
}
// MARK: - Types
class Cell: UITableViewCell {
var item: Item? {
didSet {
self.textLabel?.text = self.item?.title
self.detailTextLabel?.text = self.item?.value
}
}
required init?(coder aDecoder: NSCoder) {
fatalError( "init(coder:) is not supported for this class" )
}
override init(style: CellStyle, reuseIdentifier: String?) {
super.init( style: .value1, reuseIdentifier: reuseIdentifier )
}
}
class Item {
var site: MPSite?
var title: String
var valueProvider: (MPSite) -> String?
var value: String? {
get {
if let site = self.site {
return self.valueProvider( site )
}
else {
return nil
}
}
}
init(title: String, valueProvider: @escaping (MPSite) -> String?) {
self.title = title
self.valueProvider = valueProvider
}
}
}
@objc
protocol MPSiteDetailObserver {
func siteDetailShouldDismiss()
}
......@@ -81,7 +81,7 @@ class MPURLUtils {
var score = 0
score += Int( pow( alpha, 2 ) * 400 )
score += Int( saturation * 200 )
score += Int( MPUtils.mirror( ratio: brightness, center: 0.85 ) * 100 )
score += Int( mirror( ratio: brightness, center: 0.85 ) * 100 )
scoresByColor[color] = score
}
......
......@@ -5,43 +5,18 @@
import Foundation
class MPUtils {
static func sha256(message: String) -> Data {
return sha256( message: message.data( using: .utf8 )! )
}
static func sha256(message: Data) -> Data {
var hash = Data( count: Int( CC_SHA256_DIGEST_LENGTH ) )
message.withUnsafeBytes { messageBytes in
hash.withUnsafeMutableBytes { hashBytes in
_ = CC_SHA256( messageBytes, CC_LONG( message.count ), hashBytes )
}
}
return hash
}
static func ratio(of value: UInt8, from: Double, to: Double) -> Double {
return from + (to - from) * (Double( value ) / Double( UInt8.max ))
}
func ratio(of value: UInt8, from: Double, to: Double) -> Double {
return from + (to - from) * (Double( value ) / Double( UInt8.max ))
}
// Map a 0-1 value such that it mirrors around a center point.
// 0 -> 0, center -> 1, 1 -> 0
static func mirror(ratio: CGFloat, center: CGFloat) -> CGFloat {
if ratio < center {
return ratio / center
} else {
return 1 - (ratio - center) / (1 - center)
}
// Map a 0-1 value such that it mirrors around a center point.
// 0 -> 0, center -> 1, 1 -> 0
func mirror(ratio: CGFloat, center: CGFloat) -> CGFloat {
if ratio < center {
return ratio / center
}
static func color(message: String) -> UIColor {
let sha256 = MPUtils.sha256( message: message )
let hue = CGFloat( self.ratio( of: sha256[0], from: 0, to: 1 ) )
let saturation = CGFloat( self.ratio( of: sha256[1], from: 0.3, to: 1 ) )
let brightness = CGFloat( self.ratio( of: sha256[2], from: 0.5, to: 0.7 ) )
return UIColor( hue: hue, saturation: saturation, brightness: brightness, alpha: 1 )
else {
return 1 - (ratio - center) / (1 - center)
}
}
......@@ -81,3 +56,45 @@ extension UIColor {
return brightness;
}
}
extension Data {
func sha256() -> Data {
var hash = Data( count: Int( CC_SHA256_DIGEST_LENGTH ) )
self.withUnsafeBytes { messageBytes in
hash.withUnsafeMutableBytes { hashBytes in
_ = CC_SHA256( messageBytes, CC_LONG( self.count ), hashBytes )
}
}
return hash
}
}
extension String {
func sha256() -> Data? {
return self.data( using: .utf8 )?.sha256()
}
func color() -> UIColor? {
guard let sha = self.sha256()
else {
return nil
}
let hue = CGFloat( ratio( of: sha[0], from: 0, to: 1 ) )
let saturation = CGFloat( ratio( of: sha[1], from: 0.3, to: 1 ) )
let brightness = CGFloat( ratio( of: sha[2], from: 0.5, to: 0.7 ) )
return UIColor( hue: hue, saturation: saturation, brightness: brightness, alpha: 1 )
}
}
extension Date {
func format(date dateStyle: DateFormatter.Style = .medium, time timeStyle: DateFormatter.Style = .medium)
-> String {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = dateStyle
dateFormatter.timeStyle = timeStyle
return dateFormatter.string( from: self )
}
}
......@@ -34,6 +34,12 @@ class MPButton: UIView {
}
}
// MARK: - Life
static func closeButton() -> MPButton {
return MPButton( title: "╳" )
}
required init?(coder aDecoder: NSCoder) {
fatalError( "init(coder:) is not supported for this class" )
}
......
......@@ -5,8 +5,8 @@
import Foundation
class MPSiteView: UIView, MPSiteObserver {
var observers = Observers<MPSiteViewObserver>()
class MPSiteHeaderView: UIView, MPSiteObserver {
let observers = Observers<MPSiteHeaderObserver>()
var site: MPSite? {
willSet {
......@@ -30,7 +30,7 @@ class MPSiteView: UIView, MPSiteObserver {
super.init( frame: .zero )
// - View
self.layoutMargins = UIEdgeInsets(top: 12, left: 12, bottom: 20, right: 12)
self.layoutMargins = UIEdgeInsets( top: 12, left: 12, bottom: 20, right: 12 )
self.layer.shadowOpacity = 1
self.layer.shadowOffset = .zero
self.layer.shadowRadius = 40
......@@ -106,7 +106,7 @@ class MPSiteView: UIView, MPSiteObserver {
self.siteButton.setImage( self.site?.image, for: .normal )
self.siteButton.setTitle( self.site?.image == nil ? self.site?.siteName: nil, for: .normal )
if let brightness = self.site?.color.brightness(), brightness < 0.1 {
if let brightness = self.site?.color?.brightness(), brightness < 0.1 {
self.siteButton.layer.shadowColor = UIColor.white.cgColor
self.settingsButton.darkBackground = true
self.recoveryButton.darkBackground = true
......@@ -124,6 +124,6 @@ class MPSiteView: UIView, MPSiteObserver {
}
@objc
protocol MPSiteViewObserver {
protocol MPSiteHeaderObserver {
func siteWasActivated(activatedSite: MPSite)
}
......@@ -5,8 +5,8 @@
import UIKit
class MPSitesView: UITableView, UITableViewDelegate, UITableViewDataSource, MPUserObserver {
var observers = Observers<MPSitesViewObserver>()
class MPSitesTableView: UITableView, UITableViewDelegate, UITableViewDataSource, MPUserObserver {
let observers = Observers<MPSitesViewObserver>()
let data = NSMutableArray()
var isSelecting = false
......@@ -238,7 +238,7 @@ class MPSitesView: UITableView, UITableViewDelegate, UITableViewDataSource, MPUs
func siteDidChange() {
PearlMainQueue {
self.nameLabel.attributedText = self.result?.attributedKey
self.indicatorView.backgroundColor = self.site?.color.withAlphaComponent( 0.85 )
self.indicatorView.backgroundColor = self.site?.color?.withAlphaComponent( 0.85 )
}
PearlNotMainQueue {
let password = self.site?.result()
......
......@@ -51,13 +51,13 @@ const char *mpw_askpass(const char *prompt) {
int pipes[2];
if (pipe( pipes ) == ERR) {
wrn( "Couldn't pipe: %s", strerror( errno ) );
wrn( "Couldn't create pipes for askpass: %s", strerror( errno ) );
return NULL;
}
pid_t pid = fork();
if (pid == ERR) {
wrn( "Couldn't fork for askpass:\n %s: %s", askpass, strerror( errno ) );
wrn( "Couldn't fork for askpass: %s", askpass, strerror( errno ) );
return NULL;
}
......@@ -83,15 +83,16 @@ const char *mpw_askpass(const char *prompt) {
return NULL;
}
if (WIFEXITED( status ) && WEXITSTATUS( status ) == EXIT_SUCCESS && answer && strlen( answer )) {
// Remove trailing newline.
if (answer[strlen( answer ) - 1] == '\n')
mpw_replace_string( answer, mpw_strndup( answer, strlen( answer ) - 1 ) );
return answer;
if (!WIFEXITED( status ) || WEXITSTATUS( status ) != EXIT_SUCCESS || !answer || !strlen( answer )) {
// askpass failed.
mpw_free_string( &answer );
return NULL;
}
mpw_free_string( &answer );
return NULL;
// Remove trailing newline.
if (answer[strlen( answer ) - 1] == '\n')
mpw_replace_string( answer, mpw_strndup( answer, strlen( answer ) - 1 ) );
return answer;
}
static const char *_mpw_getline(const char *prompt, bool silent) {
......
......@@ -238,7 +238,7 @@ int main(const int argc, char *const argv[]) {
if (operation.site) {
dbg( "siteName : %s", operation.site->name );
dbg( "siteCounter : %u", operation.siteCounter );
dbg( "resultType : %s (%u)", mpw_nameForType( operation.resultType ), operation.resultType );
dbg( "resultType : %s (%u)", mpw_shortNameForType( operation.resultType ), operation.resultType );
dbg( "resultParam : %s", operation.resultParam );
dbg( "keyPurpose : %s (%u)", mpw_nameForPurpose( operation.keyPurpose ), operation.keyPurpose );
dbg( "keyContext : %s", operation.keyContext );
......
......@@ -96,7 +96,7 @@ const char *mpw_siteResult(
return NULL;
trc( "-- mpw_siteResult (algorithm: %u)", algorithmVersion );
trc( "resultType: %d (%s)", resultType, mpw_nameForType( resultType ) );
trc( "resultType: %d (%s)", resultType, mpw_shortNameForType( resultType ) );
trc( "resultParam: %s", resultParam );
char *sitePassword = NULL;
......@@ -168,7 +168,7 @@ const char *mpw_siteState(
return NULL;
trc( "-- mpw_siteState (algorithm: %u)", algorithmVersion );
trc( "resultType: %d (%s)", resultType, mpw_nameForType( resultType ) );
trc( "resultType: %d (%s)", resultType, mpw_shortNameForType( resultType ) );
trc( "resultParam: %zu bytes = %s", sizeof( resultParam ), resultParam );
if (!masterKey || !resultParam)
return NULL;
......
......@@ -482,7 +482,7 @@ static MPMarshalledUser *mpw_marshal_read_flat(
}
if (strcmp( headerName, "Default Type" ) == 0) {
int value = atoi( headerValue );
if (!mpw_nameForType( (MPResultType)value )) {
if (!mpw_shortNameForType( (MPResultType)value )) {
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %s", headerValue ) };
return NULL;
}
......@@ -564,7 +564,7 @@ static MPMarshalledUser *mpw_marshal_read_flat(
if (siteName && str_type && str_counter && str_algorithm && str_uses && str_lastUsed) {
MPResultType siteType = (MPResultType)atoi( str_type );
if (!mpw_nameForType( siteType )) {
if (!mpw_shortNameForType( siteType )) {
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %s", siteName, str_type ) };
return NULL;
}
......@@ -703,7 +703,7 @@ static MPMarshalledUser *mpw_marshal_read_json(
}
MPAlgorithmVersion algorithm = (MPAlgorithmVersion)value;
MPResultType defaultType = (MPResultType)mpw_get_json_int( json_file, "user.default_type", MPResultTypeDefault );
if (!mpw_nameForType( defaultType )) {
if (!mpw_shortNameForType( defaultType )) {
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid user default type: %u", defaultType ) };
return NULL;
}
......@@ -745,7 +745,7 @@ static MPMarshalledUser *mpw_marshal_read_json(
}
MPAlgorithmVersion siteAlgorithm = (MPAlgorithmVersion)value;
MPResultType siteType = (MPResultType)mpw_get_json_int( json_site.val, "type", (int32_t)user->defaultType );
if (!mpw_nameForType( siteType )) {
if (!mpw_shortNameForType( siteType )) {
*error = (MPMarshalError){ MPMarshalErrorIllegal, mpw_str( "Invalid site type: %s: %u", siteName, siteType ) };
return NULL;
}
......
......@@ -54,34 +54,34 @@ const MPResultType mpw_typeWithName(const char *typeName) {
}
// Find what password type is represented by the type name.
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateMaximum ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeTemplateMaximum ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeTemplateMaximum;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateLong ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeTemplateLong ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeTemplateLong;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateMedium ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeTemplateMedium ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeTemplateMedium;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateBasic ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeTemplateBasic ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeTemplateBasic;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateShort ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeTemplateShort ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeTemplateShort;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplatePIN ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeTemplatePIN ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeTemplatePIN;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplateName ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeTemplateName ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeTemplateName;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeTemplatePhrase ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeTemplatePhrase ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeTemplatePhrase;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeStatefulPersonal ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeStatefulPersonal ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeStatefulPersonal;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeStatefulDevice ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeStatefulDevice ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeStatefulDevice;
if (mpw_strncasecmp( mpw_nameForType( MPResultTypeDeriveKey ), typeName, strlen( typeName ) ) == 0)
if (mpw_strncasecmp( mpw_shortNameForType( MPResultTypeDeriveKey ), typeName, strlen( typeName ) ) == 0)
return MPResultTypeDeriveKey;
dbg( "Not a generated type name: %s", typeName );
return (MPResultType)ERR;
}
const char *mpw_nameForType(MPResultType resultType) {
const char *mpw_shortNameForType(MPResultType resultType) {
switch (resultType) {
case MPResultTypeTemplateMaximum:
......@@ -113,6 +113,38 @@ const char *mpw_nameForType(MPResultType resultType) {
}
}
const char *mpw_longNameForType(MPResultType resultType) {
switch (resultType) {
case MPResultTypeTemplateMaximum:
return "Maximum Security Password";
case MPResultTypeTemplateLong:
return "Long Password";
case MPResultTypeTemplateMedium:
return "Medium Password";
case MPResultTypeTemplateBasic:
return "Basic Password";
case MPResultTypeTemplateShort:
return "Short Password";
case MPResultTypeTemplatePIN:
return "PIN";
case MPResultTypeTemplateName:
return "Name";
case MPResultTypeTemplatePhrase:
return "Phrase";
case MPResultTypeStatefulPersonal:
return "Personal Password";
case MPResultTypeStatefulDevice:
return "Device Private Password";
case MPResultTypeDeriveKey:
return "Crypto Key";
default: {
dbg( "Unknown password type: %d", resultType );
return NULL;
}
}
}
const char **mpw_templatesForType(MPResultType type, size_t *count) {
if (!(type & MPResultTypeClassTemplate)) {
......
......@@ -147,9 +147,13 @@ const char *mpw_scopeForPurpose(MPKeyPurpose purpose);
*/
const MPResultType mpw_typeWithName(const char *typeName);
/**
* @return The standard name for the given password type.
* @return The standard identifying name for the given password type.
*/
const char *mpw_nameForType(MPResultType resultType);
const char *mpw_shortNameForType(MPResultType resultType);
/**
* @return The descriptive name for the given password type.
*/
const char *mpw_longNameForType(MPResultType resultType);
/**
* @return A newly allocated array of internal strings that express the templates to use for the given type.
......
......@@ -22,9 +22,6 @@ public final class Platform {
if (null != (tryPlatform = construct( "com.lyndir.masterpassword.gui.util.platform.JDK9Platform" )))
activePlatform = tryPlatform;
else if (null != (tryPlatform = construct( "com.lyndir.masterpassword.gui.util.platform.ApplePlatform" )))
activePlatform = tryPlatform;
else
activePlatform = new BasePlatform();
}
......
package com.lyndir.masterpassword.gui.util.platform;
import com.apple.eawt.*;
import com.apple.eio.FileManager;
import com.google.common.base.Preconditions;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.io.*;
import java.net.URI;
/**
* @author lhunath, 2018-07-29
*/
public class ApplePlatform implements IPlatform {
private static final Logger logger = Logger.get( ApplePlatform.class );
private static final Application application = Preconditions.checkNotNull(
Application.getApplication(), "Not an Apple Java application." );
private AppForegroundListener appForegroundHandler;
private AppReOpenedListener appReopenHandler;
@Override
public boolean installAppForegroundHandler(final Runnable handler) {
if (appForegroundHandler == null)
application.addAppEventListener( appForegroundHandler = new AppForegroundListener() {
@Override
public void appMovedToBackground(final AppEvent.AppForegroundEvent e) {
}
@Override
public void appRaisedToForeground(final AppEvent.AppForegroundEvent e) {
handler.run();
}
} );
return true;
}
@Override
public boolean removeAppForegroundHandler() {
if (appForegroundHandler == null)
return false;
application.removeAppEventListener( appForegroundHandler );
return true;
}
@Override
public boolean installAppReopenHandler(final Runnable handler) {
application.addAppEventListener( appReopenHandler = e -> handler.run() );
return true;
}
@Override
public boolean removeAppReopenHandler() {
if (appReopenHandler == null)
return false;
application.removeAppEventListener( appReopenHandler );
return true;
}
@Override
public boolean requestForeground() {
application.requestForeground( true );
return true;
}
@Override
public boolean show(final File file) {
try {
return FileManager.revealInFinder( file );
}
catch (final FileNotFoundException e) {
logger.err( e, "While showing: %s", file );
return false;
}
}
@Override
public boolean open(final URI url) {
try {
FileManager.openURL( url.toString() );
return true;
}
catch (final IOException e) {
logger.err( e, "While opening: %s", url );
return false;
}
}
}