Skip to content
This repository was archived by the owner on Sep 8, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Secretly.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
objects = {

/* Begin PBXBuildFile section */
3013628D269A91E50001580D /* KeychainError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3013628C269A91E50001580D /* KeychainError.swift */; };
301649F7268F967E00F26F4D /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 301649F6268F967E00F26F4D /* KeychainStore.swift */; };
302B5845267E658E007133E6 /* HttpResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B583D267E658E007133E6 /* HttpResponse.swift */; };
302B5846267E658E007133E6 /* AmacaConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B583E267E658E007133E6 /* AmacaConfig.swift */; };
302B5847267E658E007133E6 /* StatusCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 302B583F267E658E007133E6 /* StatusCode.swift */; };
Expand Down Expand Up @@ -52,6 +54,7 @@
30C77CB4266AF47300A888DC /* Credentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C77CB3266AF47300A888DC /* Credentials.swift */; };
30C77CB6266AF48300A888DC /* CurrentUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C77CB5266AF48300A888DC /* CurrentUser.swift */; };
30C77CB8266BD44300A888DC /* CreatePostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30C77CB7266BD44300A888DC /* CreatePostViewController.swift */; };
30FBE8602690E26D00557F41 /* KeychainStoreServiceTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FBE85F2690E26D00557F41 /* KeychainStoreServiceTest.swift */; };
30FD0E722659645A006E309A /* Faker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30FD0E712659645A006E309A /* Faker.swift */; };
E021984723FA35E00025C28E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E021984623FA35E00025C28E /* AppDelegate.swift */; };
E021984923FA35E00025C28E /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E021984823FA35E00025C28E /* SceneDelegate.swift */; };
Expand All @@ -73,6 +76,8 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
3013628C269A91E50001580D /* KeychainError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainError.swift; sourceTree = "<group>"; };
301649F6268F967E00F26F4D /* KeychainStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStore.swift; sourceTree = "<group>"; };
302B583D267E658E007133E6 /* HttpResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpResponse.swift; sourceTree = "<group>"; };
302B583E267E658E007133E6 /* AmacaConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AmacaConfig.swift; sourceTree = "<group>"; };
302B583F267E658E007133E6 /* StatusCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusCode.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -118,6 +123,7 @@
30C77CB3266AF47300A888DC /* Credentials.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Credentials.swift; sourceTree = "<group>"; };
30C77CB5266AF48300A888DC /* CurrentUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentUser.swift; sourceTree = "<group>"; };
30C77CB7266BD44300A888DC /* CreatePostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePostViewController.swift; sourceTree = "<group>"; };
30FBE85F2690E26D00557F41 /* KeychainStoreServiceTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStoreServiceTest.swift; sourceTree = "<group>"; };
30FD0E712659645A006E309A /* Faker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Faker.swift; sourceTree = "<group>"; };
E021984323FA35E00025C28E /* Secretly.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Secretly.app; sourceTree = BUILT_PRODUCTS_DIR; };
E021984623FA35E00025C28E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -207,9 +213,11 @@
isa = PBXGroup;
children = (
30BC8BA32662BDEF00F7E6A5 /* ImageStore.swift */,
301649F6268F967E00F26F4D /* KeychainStore.swift */,
30BC8BA52662C02300F7E6A5 /* CacheImage.swift */,
30BC8BA12662BB0000F7E6A5 /* DataContainer.swift */,
30BC8B9F2662B8A700F7E6A5 /* StorageType.swift */,
3013628C269A91E50001580D /* KeychainError.swift */,
);
path = Storage;
sourceTree = "<group>";
Expand Down Expand Up @@ -282,6 +290,7 @@
children = (
E021985D23FA35E20025C28E /* SecretlyTests.swift */,
E021985F23FA35E20025C28E /* Info.plist */,
30FBE85F2690E26D00557F41 /* KeychainStoreServiceTest.swift */,
);
path = SecretlyTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -411,6 +420,7 @@
E021984B23FA35E00025C28E /* WelcomeViewController.swift in Sources */,
3072FBDF2680FA5A00B35C8C /* ImageProcessor.swift in Sources */,
302BB622267E38E800FD74F5 /* PostInputViewController+UIImagePickerControllerDelegate.swift in Sources */,
3013628D269A91E50001580D /* KeychainError.swift in Sources */,
302B5845267E658E007133E6 /* HttpResponse.swift in Sources */,
302B584A267E658E007133E6 /* RestClient.swift in Sources */,
302B5848267E658E007133E6 /* HttpClient.swift in Sources */,
Expand All @@ -430,6 +440,7 @@
3033795D267537B40066D94A /* FeedCollectionViewController+UICollectionViewDelegateFlowLayout .swift in Sources */,
30BC8BA82662CEBA00F7E6A5 /* Checksum.swift in Sources */,
30FD0E722659645A006E309A /* Faker.swift in Sources */,
301649F7268F967E00F26F4D /* KeychainStore.swift in Sources */,
30337957267536E30066D94A /* FeedCollectionViewController+UICollectionViewDelegate.swift in Sources */,
307A305E2661CD510020DF8B /* PostCollectionViewCell.swift in Sources */,
302BB626267E447900FD74F5 /* PostInputViewController+UITextFieldDelegate.swift in Sources */,
Expand Down Expand Up @@ -461,6 +472,7 @@
buildActionMask = 2147483647;
files = (
E021985E23FA35E20025C28E /* SecretlyTests.swift in Sources */,
30FBE8602690E26D00557F41 /* KeychainStoreServiceTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
2 changes: 1 addition & 1 deletion Secretly/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" translatesAutoresizingMaskIntoConstraints="NO" id="TPK-s3-R7J">
<rect key="frame" x="0.0" y="56" width="414" height="703"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<collectionViewFlowLayout key="collectionViewLayout" automaticEstimatedItemSize="YES" minimumLineSpacing="10" minimumInteritemSpacing="10" id="pv6-US-yae">
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="8" minimumInteritemSpacing="8" id="pv6-US-yae">
<size key="itemSize" width="128" height="128"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
Expand Down
8 changes: 4 additions & 4 deletions Secretly/Models/CurrentUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

class CurrentUser {
static func load() -> CurrentUser? {
guard let username = UserDefaults.standard.string(forKey: "secretly.username") else {
guard let username = try? KeychainStore.common.getItem(forKey: "secretly.username") else {
return nil
}
return CurrentUser(username: username)
Expand All @@ -20,7 +20,7 @@ class CurrentUser {

init(username: String) {
self.username = username
UserDefaults.standard.set(username, forKey: "secretly.username")
_ = KeychainStore.common.setItem(key: "secretly.username", value: username)
}

func credentials() -> Credentials {
Expand All @@ -32,12 +32,12 @@ class CurrentUser {
}

private func password() -> String? {
return UserDefaults.standard.string(forKey: "secretly.password")
return try? KeychainStore.common.getItem(forKey: "secretly.password")
}

private func genPassword() -> String {
let newPsswd = UUID().uuidString
UserDefaults.standard.set(newPsswd, forKey: "secretly.password")
_ = KeychainStore.common.setItem(key: "secretly.password", value: newPsswd)
return newPsswd
}
}
7 changes: 4 additions & 3 deletions Secretly/Network/AmacaConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ import Foundation
struct AmacaConfig {
static let shared = AmacaConfig()
var host: String {
values["host"] as! String
return values["host"] as! String
}
var httpClient: HttpClient {
HttpClient(session: URLSession.shared, baseUrl: host)
}

var apiToken: String? {
get {
UserDefaults.standard.string(forKey: "amaca.apitoken")
try? KeychainStore.common.getItem(forKey: "amaca.apitoken")

}
}

func setApiToken(_ value: String) {
UserDefaults.standard.set(value, forKey: "amaca.apitoken")
_ = KeychainStore.common.setItem(key: "amaca.apitoken", value: value)
}

private var filepath: String {
Expand Down
15 changes: 15 additions & 0 deletions Secretly/Storage/KeychainError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// KeychainError.swift
// Secretly
//
// Created by Luis Abraham Ortega Gonzalez on 10/07/21.
// Copyright © 2021 3zcurdia. All rights reserved.
//

import Foundation

enum KeychainError: Error {
case noItem
case unexpectedItemData
case unhandledError(status: OSStatus)
}
133 changes: 133 additions & 0 deletions Secretly/Storage/KeychainStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// KeychainService.swift
// Secretly
//
// Created by Luis Abraham Ortega Gonzalez on 02/07/21.
// Copyright © 2021 3zcurdia. All rights reserved.
//

import Foundation


struct KeychainStore{

public let serviceName:String?

private static let defaultServiceName: String = {
return Bundle.main.bundleIdentifier ?? "com.secretly.ioslab"
}()

public static let common = KeychainStore()

public init(serviceName:String? = nil){
self.serviceName = serviceName
}

private init(){
self.init(serviceName: KeychainStore.defaultServiceName)
}



public func setItem(key :String, value: String, accesibility: CFString? = nil) -> Bool {
let encodedValue = value.data(using: String.Encoding.utf8)!
return self.set(key: key, value: encodedValue, accesibility: accesibility)
}


private func set(key :String, value: Data, accesibility: CFString? = nil) -> Bool{
var query = self.setUpKeychainDic(key: key,accesibility: accesibility)

query[kSecValueData as String] = value

let status = SecItemAdd(query as CFDictionary, nil)
if status == errSecSuccess {
return true
} else if status == errSecDuplicateItem {
return self.updateItem(key: key, value: value, accesibility: accesibility)
} else {
return false
}
}

private func updateItem(key:String, value:Data, accesibility: CFString? = nil) -> Bool {

let query = self.setUpKeychainDic(key: key, accesibility: accesibility)
let update:[String:Any] = [kSecValueData as String:value]

let status = SecItemUpdate(query as CFDictionary, update as CFDictionary)

if status == errSecSuccess {
return true
} else {
return false
}
}


public func getItem(forKey key: String) throws -> String{
var query = self.setUpKeychainDic(key: key)
query[kSecReturnAttributes as String] = true
query[kSecReturnData as String] = true
query[kSecMatchLimit as String] = kSecMatchLimitOne

var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)


guard status != errSecItemNotFound else { throw KeychainError.noItem }
guard status == errSecSuccess else { throw KeychainError.unhandledError(status: status) }

guard let existingItem = item as? [String : Any],
let itemData = existingItem[kSecValueData as String] as? Data,
let stringData = String(data: itemData, encoding: String.Encoding.utf8)
else {
throw KeychainError.unexpectedItemData
}

return stringData
}


public func deleteItem(forKey key: String, accesibility: CFString? = nil) -> Bool{
let query = self.setUpKeychainDic(key: key, accesibility: accesibility)
let status: OSStatus = SecItemDelete(query as CFDictionary)
if status == errSecSuccess {
return true
} else {
return false
}

}

public func deleteAllItems() -> Bool {
var query = [String:Any]()
query[kSecClass as String] = kSecClassInternetPassword
query[kSecAttrServer as String] = self.serviceName ?? KeychainStore.defaultServiceName

let status: OSStatus = SecItemDelete(query as CFDictionary)
if status == errSecSuccess {
return true
} else {
return false
}
}

private func setUpKeychainDic(key: String, accesibility: CFString? = nil) -> [String:Any]{
var keychainQueryDictionary: [String:Any] = [String: Any]()
// Uniquely identify this keychain accessor
let encodedIdentifier: Data? = key.data(using: String.Encoding.utf8)
keychainQueryDictionary[kSecClass as String] = kSecClassInternetPassword
keychainQueryDictionary[kSecAttrDescription as String] = encodedIdentifier
keychainQueryDictionary[kSecAttrAccount as String] = encodedIdentifier
keychainQueryDictionary[kSecAttrServer as String] = self.serviceName ?? KeychainStore.defaultServiceName

if let accessString = accesibility {
keychainQueryDictionary[kSecAttrAccessible as String] = accessString
}


return keychainQueryDictionary
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ extension FeedCollectionViewController: UICollectionViewDataSource {
cell.post = self.posts?[indexPath.row]
return cell
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@
import UIKit

extension FeedCollectionViewController: UICollectionViewDelegateFlowLayout {


func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: 300)
let numberOfItemsPerRow:CGFloat = 1
let flowLayout = collectionViewLayout as! UICollectionViewFlowLayout

let totalSpacing = Int(flowLayout.sectionInset.left) + Int(flowLayout.sectionInset.right) + Int((numberOfItemsPerRow-1) * flowLayout.minimumInteritemSpacing)
let width = (Int(collectionView.bounds.width) - totalSpacing)/Int(numberOfItemsPerRow)
return CGSize(width: width, height: 300)
}

}
7 changes: 6 additions & 1 deletion Secretly/ViewControllers/FeedCollectionViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,19 @@ class FeedCollectionViewController: UIViewController {
}

func setupCollectionView() {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 4
layout.minimumInteritemSpacing = 4
layout.sectionInset = UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
postInputView.delegate = self
collectionView.delegate = self
collectionView.dataSource = self
collectionView.prefetchDataSource = self
// collectionView.isPrefetchingEnabled = true
collectionView.collectionViewLayout = layout
let nib = UINib(nibName: String(describing: PostCollectionViewCell.self), bundle: nil)
collectionView.register(nib, forCellWithReuseIdentifier: PostCollectionViewCell.reuseIdentifier)
collectionView.addSubview(refreshControl)

refreshControl.addTarget(self, action: #selector(self.loadPosts), for: UIControl.Event.valueChanged)
}

Expand Down
6 changes: 6 additions & 0 deletions Secretly/Views/PostCollectionViewCell.xib
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
<constraint firstAttribute="height" constant="300" id="FVk-cX-Y87"/>
<constraint firstAttribute="width" secondItem="LcI-IM-E3b" secondAttribute="height" multiplier="4:3" id="IcI-he-Eb8"/>
</constraints>
<variation key="default">
<mask key="constraints">
<exclude reference="FVk-cX-Y87"/>
<exclude reference="IcI-he-Eb8"/>
</mask>
</variation>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="lorem ipsum dolor quet" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mh0-Gr-U1B">
<rect key="frame" x="20" y="135.5" width="360" height="29"/>
Expand Down
Loading