iOS/Swift: directly manipulate remote MySQL over SSH - ios

is it possible to read, write, ... to/from a MySQL-database hosted on a remote server? I.e. can I connect to the database via SSH and directly make CRUD operations?
Is SSH possible/allowed in iOS, e.g. copying over images to a remote server etc.?

You could use a framework like NMSSH - see it here on Github.
Here is an usage example taken from a project by cagnulein:
var host = "your-host.com"
var username = "user"
var password = "pass"
var session = NMSSHSession(host: host, andUsername: username)
session.connect()
if session.connected == true {
session.authenticateByPassword(password)
if session.authorized == true {
NSLog("Authentication succeeded")
}
var error = NSErrorPointer()
var response = session.channel.execute("ls", error: error)
NSLog("List of my files %#", response)
}
session.disconnect()
Swift 4 & latest NMSSH version
do {
let host = "example.com"
let username = "user"
let password = "pass"
let session = NMSSHSession(host: host, andUsername: username)
session?.connect()
if session?.isConnected ?? false {
session?.authenticate(byPassword: password)
if session?.isAuthorized ?? false {
print("Authentication succeeded")
}
let response = try session?.channel.execute("ls")
print("List of my files:", response)
}
session?.disconnect()
} catch {
print(error)
}

Related

GRPC-Swift Send HTTPProtocolVersion from Client

I'm trying GRPC-Swift for Client-Server application.
I'm using GRPC-Swift for both Client and Server
Client is an iPhone application, which I tried with iPhone Simulator.
I followed this link for Client-side streaming RPC.
When I send message to Server from Client, I got the following error message in the console from Server,
error io.grpc.server_channel_call : unable to determine http version
From the Server in the
HTTPProtocolSwitcher.swift
inside the function func channelRead(context: ChannelHandlerContext, data: NIOAny), it is checking for HTTPProtocolVersion, and it is missing.
How to send the HTTPVersion from the Client code?
Update:
Client Code
import GRPC
import NIO
class HTTPClient {
private let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
private var channel: ClientConnection?
private var client: ChatGuide_ChatGuideClient?
private var clientCall: ClientStreamingCall<ChatGuide_TextMessage, ChatGuide_TextMessage>?
func connect(host: String, port: Int) throws {
let channel = ClientConnection.secure(group: self.group)
.connect(host: host, port: port)
self.channel = channel
self.client = ChatGuide_ChatGuideClient(channel: channel)
}
func disconnect() {
do {
self.clientCall?.sendEnd(promise: nil)
_ = try self.clientCall?.status.wait()
try self.group.syncShutdownGracefully()
} catch let error {
print("\(type(of: self)): Could not shutdown gracefully -", error.localizedDescription)
}
}
func initiateClient() {
let timeAmount = TimeAmount.minutes(1)
let timeLimit = TimeLimit.timeout(timeAmount)
let options = CallOptions(timeLimit: timeLimit)
let call = self.client?.chat(callOptions: options)
call?.response.whenSuccess { (message) in
print("\(type(of: self)): Message from server -", message.text)
}
call?.response.whenFailure { (error) in
print("\(type(of: self)): Response error -", error.localizedDescription)
}
self.clientCall = call
}
func send(text: String) {
if self.clientCall == nil {
self.initiateClient()
}
let message = ChatGuide_TextMessage.with {
$0.text = text
}
self.clientCall?.sendMessage(message, promise: nil)
}
}
Hey Vignesh,
I am currently learning gRPC-Swift myself, so I hope I will be of service and not muck things further.
However, it looks to me that you are not configuring the HTTP/1.x layer in order to transfer Protobuf packets, if you take a look at the HTTP1ToGRPCServerCodec.swift file Here
I think you will have a much clearer idea of how to adjust your code, I am sorry I can't provide more details, however not being too sure myself without further testing and reviewing the codebase.
Best regards and keep me posted if indeed i was helpful,
cheers
From the Server I have initiated insecure Server as,
let server = Server.insecure(group: self.group)
From the Client I have initiated secure ClientConnection as,
let channel = ClientConnection.secure(group: self.group)
And I got this clarification from here
So I made the ClientConnection also insecure as,
let channel = ClientConnection.insecure(group: self.group)
And after this it is working now.

pjsip connect to asterisk trouble

I have added pjsip lib through cocoapods from here https://github.com/chebur/pjsip.
No I'm trying to connect to sip server using this pjsip example.
Here is my code:
func startPjsip() {
var status: pj_status_t
// Create pjsua first
status = pjsua_create()
if status != Int32(PJ_SUCCESS.rawValue) {
pjsuaError("Error in pjsua_create()", status: status)
}
// Init Pjsua
var config = pjsua_config()
pjsua_config_default(&config)
// on reg state
config.cb.on_reg_state = { (accountId: pjsua_acc_id) in
p("on_reg_state", accountId)
}
// Init the logging config structure
var logConfig = pjsua_logging_config()
pjsua_logging_config_default(&logConfig)
logConfig.console_level = 4
// Init the pjsua
status = pjsua_init(&config, &logConfig, nil)
if status != Int32(PJ_SUCCESS.rawValue) {
pjsuaError("Error in pjsua_init()", status: status)
}
// Adding UDP transport
// Init transport config structure
var udpTransportConfig = pjsua_transport_config()
pjsua_transport_config_default(&udpTransportConfig)
udpTransportConfig.port = 5060
status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &udpTransportConfig, nil)
if status != Int32(PJ_SUCCESS.rawValue) {
pjsuaError("Error in creating UDP transport", status: status)
}
// Initialization is done, now start pjsua
status = pjsua_start()
if status != Int32(PJ_SUCCESS.rawValue) {
pjsuaError("Error starting pjsua", status: status)
}
// Register the account on local sip server
var accountConfig = pjsua_acc_config()
pjsua_acc_config_default(&accountConfig)
// username
let username = "10001"
let domain = "voip01.interpreters.travel"
let userId = "sip:\(username)#\(domain)"
accountConfig.id = pj_str_t(ptr: stringToPointer(string: userId), slen: pj_ssize_t(userId.characters.count))
// uri
var uri = "sip:\(domain)"
accountConfig.reg_uri = pj_str_t(ptr: stringToPointer(string: uri), slen: pj_ssize_t(uri.characters.count))
accountConfig.cred_count = 1
accountConfig.cred_info.0.realm = pj_str_t(ptr: stringToPointer(string: "*"), slen: pj_ssize_t("*".characters.count))
let scheme = "digest"
accountConfig.cred_info.0.scheme = pj_str_t(ptr: stringToPointer(string: scheme), slen: pj_ssize_t(scheme.characters.count))
accountConfig.cred_info.0.data_type = Int32(PJSIP_CRED_DATA_PLAIN_PASSWD.rawValue)
let password = "10001"
accountConfig.cred_info.0.data = pj_str_t(ptr: stringToPointer(string: password), slen: pj_ssize_t(password.characters.count))
accountConfig.cred_info.0.username = pj_str_t(ptr: stringToPointer(string: username), slen: pj_ssize_t(username.characters.count))
var accountId = pjsua_acc_id()
status = pjsua_acc_add(&accountConfig, pj_bool_t(PJ_TRUE.rawValue), &accountId)
p(accountId)
if status != Int32(PJ_SUCCESS.rawValue) {
pjsuaError("Error adding account", status: status)
}
}
func pjsuaError(_ message: String, status: pj_status_t) {
let url = NSURL(fileURLWithPath: #file)
let fileName: String = url.lastPathComponent == nil ? #file : url.lastPathComponent!
pjsua_perror(fileName, message, status)
pjsua_destroy()
}
func stringToPointer(string: String) -> UnsafeMutablePointer<Int8> {
let cs = (string as NSString).utf8String
return UnsafeMutablePointer<Int8>(mutating: cs!)
}
When I run application I've got request sending to sip server, it returns 401 Unauthorized (log is here), which seems to be fine according to this doc.
After that pjsip send another request and sip server return 403 Forbidden, here is the log.
I've asked my server guy what is the problem and he said that he used the same credentials with JsSIP lib for browser client and everything works fine for him. Here is the log he gave to me.
I have looked at his log and see difference in these lines:
mine - Via: SIP/2.0/UDP
his - Via: SIP/2.0/WSS
So seems that I'm using wrong transport protocol. But I don't know how to set pjsip to use wss protocol.
Can someone help me if you have the same issues. Or what I need to read/try to achieve my goal.
UPDATE:
I have added Starscream, and got it working to connect to wss:// url. Here is the code:
var socket: WebSocket!
override func viewDidLoad() {
super.viewDidLoad()
socket = WebSocket(url: URL(string: "wss://voip01.interpreters.travel:4443")!)
socket.delegate = self
socket.pongDelegate = self
socket.headers["Sec-WebSocket-Protocol"] = "sip"
socket.connect()
}
func websocketDidConnect(socket: WebSocket) {
print("websocketDidConnect")
print(socket)
}
It says "websocketDidConnect". But now I need to send SIP REGISTER through this wss transport protocol. I can't find any information how to setup pjsip to use wss.
I have tried to change pjsua_transport_create with PJSIP_TRANSPORT_TCP or TLS but no success.
Please, can someone help me where to find information about pjsip + websocket support.

related to the xmppframework and openfire server in ios

I am implementing XMPP framework and trying to connect the openfire server in swift, but I don't understand following line.
"stream.myJID = XMPPJID.jidWithString("xxxxxx")"
So, which jid will provide in stream.myjid.
Yes. First you will add xmppRoster or xmppRoom in xmppStream by activating it. And then you will try to connect by giving your JID and password to authorize. Your JID can be anything that can be uniquely defined like userName#ServerUrl. Like this:
let jabberID = "\(username)#\(Constants.Url.chatBaseUrl)"
self.password = "12345"
if !xmppStream.isDisconnected() {
return true
}
if jabberID == "" && self.password == "" {
return false
}
xmppStream.myJID = XMPPJID.jidWithString(jabberID)
do {
try xmppStream.connectWithTimeout(XMPPStreamTimeoutNone)
print("Connection success")
return true
} catch {
print("Something went wrong!")
return false
}

AWS iOS SDK AWSServiceManager multiple service configurations

I've integrated the AWS iOS SDK (v.2.3.6) into my application. It works fine and good, except that I've noticed that defaultServiceManager has a disclaimer:
"You should use this singleton method instead of creating an instance of the service manager".
I ordinarily wouldn't have an issue with this, except it's defaultServiceConfiguration is immutable:
"This property can be set only once, and any subsequent setters are ignored."
I have a requirement that a service configuration (ie. identityPoolId + region) be able to change at runtime.
What are the possible ways around this? I'd love to be able to just reset the service configuration at any point, but that's unlikely given what the documentation says.
You should not mutate the default service configuration. Instead, each service client provides the following class methods:
+ register[ServiceClientName]WithConfiguration:forKey:
+ [ServiceClientName]ForKey:
For example, for AWSS3TransferUtility, they are:
+ registerS3TransferUtilityWithConfiguration:forKey:
+ S3TransferUtilityForKey:
In this way, you can pass a different service configuration for each service client in the runtime. By following this pattern, you can avoid the unintentionally "polluted" default service configuration bugs that can be very difficult to debug.
To use the custom configurations with each upload you can create temporary access key and secret with a session. Then you can use those keys to upload your file. Below is the code snippet
/// This function is used to authorize user with AWS.
private func connectWithAWS() -> AWSServiceConfiguration? {
/// Simple session credentials with keys and session token.
let credentialsProvider = AWSBasicSessionCredentialsProvider.init(accessKey: "TEMPORARY ACCESS KEY", secretKey: "TEMPORARY SECRET KEY", sessionToken: "TEMPORARY SESSION")
/// A service configuration object.
guard let configuration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider) else {
return nil
}
return configuration
}
func uploadFileToS3() {
/// Get configurations for bucket
guard let configuration = connectWithAWS() else {
///AWSServiceConfiguration Not Initialised.
return
}
///Check if a AWSS3TransferUtility already exist for current access key or not.
let trans = AWSS3TransferUtility.s3TransferUtility(forKey: "TEMPORARY ACCESS KEY")
if trans == nil {
/// If AWSS3TransferUtility is nil than create new for a access id
///
AWSS3TransferUtility.register(with: configuration, transferUtilityConfiguration: nil, forKey: "TEMPORARY ACCESS KEY") { (err) in
print("Error in AWSS3TransferUtility.register: ->>> \(err?.localizedDescription ?? "")")
}
}
///
/// Check if a AWSS3TransferUtility already exist for current access key or not.
guard let transferUtility = AWSS3TransferUtility.s3TransferUtility(forKey: "TEMPORARY ACCESS KEY") else {
return
}
///
/// Start Uploading process
///
let expression = AWSS3TransferUtilityUploadExpression()
expression.setValue("public-read", forRequestHeader: "x-amz-acl")
let s3BucketName = "BUCKET NAME"
let url = URL.init(fileURLWithPath: "fileURL")
transferUtility.uploadFile(url, bucket: s3BucketName, key: "fileName", contentType: "contentType", expression: expression) { (task, error) in
if error != nil {
print("Upload failed ❌ (\(error!))")
return
}
if task.status == AWSS3TransferUtilityTransferStatusType.completed {
let s3URL = "https://\(s3BucketName).s3.amazonaws.com/\(task.key)"
print("Uploaded to:\n\(s3URL)")
return
} else {
print("Not uploaded")
}
}.continueWith { (task) -> Any? in
if let error = task.error {
print("Upload failed ❌ (\(error))")
}
if task.result != nil, task.isCompleted == true {
let s3URL = "https://\(s3BucketName).s3.amazonaws.com/\(task.result!.key)"
print("Uploading Start of : \(s3URL)")
} else {
print("Unexpected empty result.")
}
return nil
}
}

How do I run a Cloud Code on Heroku?

With the Parse's announcement of their retirement, I have migrated my Parse Server onto Heroku. With my still neophyte knowledge of Heroku, I do not know if they have a similar function to that of Cloud Code, but I do know that a few months ago Parse Introduced a Heroku + Parse feature that allows you to run Cloud Code on any node.js environment, particularly Heroku.
My dilemma is, I have already migrated my server from parse to Heroku prior to learning about this feature :/ , so I cannot run any parse cloud code form my terminal because there is no existing server there anymore. So the question is, how can I emulate this following Cloud Code in Heroku & How do I adjust my swift?
Cloud Code:
// Use Parse.Cloud.define to define as many cloud functions as you want.
// For example:
Parse.Cloud.define("isLoginRedundant", function(request, response) {
Parse.Cloud.useMasterKey();
var sessionQuery = new Parse.Query(Parse.Session);
sessionQuery.equalTo("user", request.user);
sessionQuery.find().then(function(sessions) {
response.success( { isRedundant: sessions.length>1 } );
}, function(error) {
response.error(error);
});
});
and here is my swift back in xcode:
PFUser.logInWithUsernameInBackground(userName!, password: passWord!) {
(user, error) -> Void in
if (user != nil) {
// don't do the segue until we know it's unique login
// pass no params to the cloud in swift (not sure if [] is the way to say that)
PFCloud.callFunctionInBackground("isLoginRedundant", withParameters: [:]) {
(response: AnyObject?, error: NSError?) -> Void in
let dictionary = response as! [String:Bool]
var isRedundant : Bool
isRedundant = dictionary["isRedundant"]!
if (isRedundant) {
// I think you can adequately undo everything about the login by logging out
PFUser.logOutInBackgroundWithBlock() { (error: NSError?) -> Void in
// update the UI to say, login rejected because you're logged in elsewhere
// maybe do a segue here?
let redundantSession: String = "you are already logged in on another device"
self.failedMessage(redundantSession)
self.activityIND.stopAnimating()
self.loginSecond.userInteractionEnabled = true
}
} else {
// good login and non-redundant, do the segue
self.performSegueWithIdentifier("loginSuccess", sender: self)
}
}
} else {
// login failed for typical reasons, update the UI
dispatch_async(dispatch_get_main_queue()) {
self.activityIND.stopAnimating()
self.loginSecond.userInteractionEnabled = true
if let message = error?.userInfo["error"] as? String
where message == "invalid login parameters" {
let localizedMessage = NSLocalizedString(message, comment: "Something isn't right, check the username and password fields and try again")
print(localizedMessage)
self.failedMessage(localizedMessage)
}else if let secondMessage = error?.userInfo["error"] as? String
where secondMessage == "The Internet connection appears to be offline." {
self.failedMessage(secondMessage)
}
}
}
}
I would first checkout the example repo and read the parse-server documentation. Parse server supports cloud code out of the box and you simply specify which file contains your functions and triggers in the parse-server config. The link you posted with the integration between parse and heroku is not relevant for parse-server.

Resources