Архив

Архив раздела ‘iOS’
9 декабря 2025 Нет комментариев

1. Подготовить файлы и sql запросы — скрипт на php (запускать дважды, первый раз файлам устанавливается дата из exif):
$pk=200; — значение должно быть больше текущего максимального в ZGENERICASSET

<?php
ini_set('date.timezone','Etc/GMT-4');
$dir=__DIR__.'/photos';
$files=scandir($dir);
$files=array_diff(scandir($dir),array('.','..'));
usort($files,function($a,$b) use ($dir){
	return filemtime($dir.'/'.$a)<=>filemtime($dir.'/'.$b);
});
$outputFile='insert_photos.sql';
$sql="BEGIN TRANSACTION;\n";
$pk=200;
$z_ent=15;
$z_opt=1;
$sql.="DELETE FROM \"ZGENERICASSET\" WHERE Z_PK>=".$pk.";\n";
$sql.="DELETE FROM \"ZADDITIONALASSETATTRIBUTES\" WHERE Z_PK>=".$pk.";\n";
$sql.="DELETE FROM \"Z_8ASSETS\" WHERE Z_14ASSETS>=".$pk.";\n";
$pk+=100;
foreach($files as $file){
	$path=$dir.'/'.$file;
	$ext=strtolower(pathinfo($file,PATHINFO_EXTENSION));
	$isVideo=($ext==='mov');
	$isImage=($ext==='jpg'||$ext==='jpeg');
	if(!$isVideo&&!$isImage)continue;
	$filename=$file;
	$title=pathinfo($file,PATHINFO_FILENAME);
	$directory='DCIM/100APPLE';
	$zuuid="X'".bin2hex(random_bytes(16))."'";
	if($isImage){
		$width=getimagesize($path)[0];
		$height=getimagesize($path)[1];
		$ZUNIFORMTYPEIDENTIFIER='public.jpeg';
		$orientation=($width>$height)?3:6;
		$add_orientation=$orientation;
		$ZKIND=0;
		$ZHIGHDYNAMICRANGETYPE=1;
		$ZORIGINALHEIGHT=($width>$height)?$height:$width;
		$ZORIGINALWIDTH=($width>$height)?$width:$height;
		$ZDURATION='0.0';
		$exif=@exif_read_data($path);
		if(!empty($exif['DateTimeOriginal'])){
			$shootTimeStr=$exif['DateTimeOriginal'];
		}
		elseif(!empty($exif['CreateDate'])){
			$shootTimeStr=$exif['CreateDate'];
		}
		elseif(!empty($exif['DateTimeDigitized'])){
			$shootTimeStr=$exif['DateTimeDigitized'];
		}
		else{
			$shootTimeStr=null;
		}
		if($shootTimeStr){
			$shootUnix=strtotime(str_replace(':','-',substr($shootTimeStr,0,10)).substr($shootTimeStr,10));
		}
		else{
			$shootUnix=filemtime($path);
		}
	}
	else{
		$width=640;
		$height=480;
		$ZUNIFORMTYPEIDENTIFIER='com.apple.quicktime-movie';
		$orientation=1;
		$add_orientation=0;
		$ZKIND=1;
		$ZHIGHDYNAMICRANGETYPE=null;
		$ZORIGINALHEIGHT=0;
		$ZORIGINALWIDTH=0;
		$ZDURATION='4.0';
		$shootUnix=filemtime($path);
	}
	touch($path,$shootUnix,$shootUnix);
	$macEpoch=strtotime('2001-01-01 00:00:00');
	$macTime=round(($shootUnix-$macEpoch)+(rand(10,99999)/100000),5);
	$originalSize=filesize($path);
	$zgenericasset=[
		'Z_PK'=>$pk,
		'Z_ENT'=>$z_ent,
		'Z_OPT'=>$z_opt,
		'ZCLOUDHASCOMMENTSBYME'=>NULL,
		'ZCLOUDHASCOMMENTSCONVERSATION'=>NULL,
		'ZCLOUDHASUNSEENCOMMENTS'=>NULL,
		'ZCLOUDPLACEHOLDERKIND'=>0,
		'ZCOMPLETE'=>1,
		'ZFLAGGED'=>0,
		'ZHEIGHT'=>$height,
		'ZKIND'=>$ZKIND,
		'ZORIENTATION'=>$orientation,
		'ZSAVEDASSETTYPE'=>3,
		'ZTHUMBNAILINDEX'=>1,
		'ZWIDTH'=>$width,
		'ZADDITIONALATTRIBUTES'=>$pk,
		'ZCLOUDBATCHPUBLISHDATE'=>NULL,
		'ZCLOUDLASTVIEWEDCOMMENTDATE'=>NULL,
		'ZDATECREATED'=>$macTime,
		'ZMODIFICATIONDATE'=>ceil($macTime),
		'ZSORTTOKEN'=>$macTime,
		'ZCLOUDASSETGUID'=>NULL,
		'ZCLOUDASSETKIND'=>NULL,
		'ZCLOUDBATCHID'=>NULL,
		'ZCLOUDCOLLECTIONGUID'=>NULL,
		'ZDIRECTORY'=>$directory,
		'ZFILENAME'=>$filename,
		'ZTITLE'=>$title,
		'ZUNIFORMTYPEIDENTIFIER'=>$ZUNIFORMTYPEIDENTIFIER,
		'ZCLOUDMETADATA'=>NULL,
		'ZFACERECTANGLES'=>NULL,
		'ZUUID'=>$zuuid,
		'ZLOCATIONDATA'=>NULL,
		'ZIMAGEURLDATA'=>NULL,
		'ZTHUMBNAILURLDATA'=>NULL,
	];
	$zadditional=[
		'Z_PK'=>$pk,
		'Z_ENT'=>1,
		'Z_OPT'=>2,
		'ZEMBEDDEDTHUMBNAILHEIGHT'=>0,
		'ZEMBEDDEDTHUMBNAILLENGTH'=>0,
		'ZEMBEDDEDTHUMBNAILOFFSET'=>0,
		'ZEMBEDDEDTHUMBNAILWIDTH'=>0,
		'ZHIGHDYNAMICRANGETYPE'=>$ZHIGHDYNAMICRANGETYPE,
		'ZORIGINALFILESIZE'=>$originalSize,
		'ZORIGINALHEIGHT'=>$ZORIGINALHEIGHT,
		'ZORIGINALORIENTATION'=>$orientation,
		'ZORIGINALWIDTH'=>$ZORIGINALWIDTH,
		'ZASSET'=>$pk,
		'Z14_ASSET'=>15,
		'ZDURATION'=>$ZDURATION,
		'ZCREATORBUNDLEID'=>NULL,
		'ZORIGINALFILENAME'=>$filename,
		'ZORIGINALPATH'=>$directory,
		'ZIMPORTSESSIONID'=>NULL,
		'ZORIGINALASSETSUUID'=>NULL,
	];
	$album=[
		'Z_8ALBUMS'=>4,
		'Z_14ASSETS'=>$pk,
		'Z_FOK_14ASSETS'=>2048,
	];
	$columns=implode(',',array_keys($zgenericasset));
	$values=implode(',',array_map(fn($v)=>is_null($v)?'NULL':(is_numeric($v)?$v:"'$v'"),$zgenericasset));
	$sql.=str_replace("'',NULL","',NULL",str_replace("NULL,'X'","NULL,X'","INSERT INTO \"ZGENERICASSET\"($columns)VALUES($values);"))."\n";
	$columns=implode(',',array_keys($zadditional));
	$values=implode(',',array_map(fn($v)=>is_null($v)?'NULL':(is_numeric($v)?$v:"'$v'"),$zadditional));
	$sql.="INSERT INTO \"ZADDITIONALASSETATTRIBUTES\"($columns)VALUES($values);\n";
	$columns=implode(',',array_keys($album));
	$values=implode(',',array_map(fn($v)=>is_null($v)?'NULL':(is_numeric($v)?$v:"'$v'"),$album));
	$sql.="INSERT INTO \"Z_8ASSETS\"($columns)VALUES($values);\n";
	$pk++;
}
$sql.="UPDATE \"Z_PRIMARYKEY\" SET Z_MAX='".$pk."' WHERE Z_NAME='AdditionalAssetAttributes';\n";
$sql.="UPDATE \"Z_PRIMARYKEY\" SET Z_MAX='".$pk."' WHERE Z_NAME='GenericAsset';\n";
$sql.="COMMIT;\n";
file_put_contents($outputFile,$sql);
echo "SQL file generated: $outputFile\n";
?>

2. В локальную резервную копию через iBackupBot импортировать фото и видео после обработки скриптом в /System Files/CameraRollDomain/Media/DCIM/100APPLE
3. Из локальной резервной копии через iBackupBot экспортировать /System Files/CameraRollDomain/Media/PhotoData/Photos.sqlite
4. В DB Browser for SQLite выполнить подготовленные запросы, записать изменения.
5. В iBackupBot импортировать БД обратно.
6. Восстановить резервную копию через iTunes

Categories: iOS Tags:
9 декабря 2025 Нет комментариев

1. Из локальной резервной копии через iBackupBot экспортировать /System Files/WirelessDomain/Library/CallHistory/call_history.db
2. Подготовить csv для загрузки в формате (выгружено через iPhoneBackupBrowser, важно: в длительности здесь важны только секунды, т.к. это полное кол-во секунд)

"From","To","Start date","Duration"
"Me","+79210000000","2013-03-01 20:00:42","0h 26m 1611s"
"+79210000000","Me","2013-03-02 10:41:52","0h 05m 335s"

3. Подготовить sql запросы — скрипт на php:

<?php
$csvFile='calls.csv';
$outputFile='insert_calls.sql';
$handle=fopen($csvFile,'r');
if(!$handle){
	die("Cannot open CSV file.\n");
}
$sql="BEGIN TRANSACTION;\n";
$header=fgetcsv($handle);
$rowId=1;
ini_set('date.timezone','Etc/GMT-3');
while(($data=fgetcsv($handle))!==false){
	list($from,$to,$startDate,$duration)=$data;
	$from=trim($from,'"');
	$to=trim($to,'"');
	$startDate=trim($startDate,'"');
	$duration=trim($duration,'"');
	preg_match('/(\d+)s$/',$duration,$matches);
	$totalSeconds=isset($matches[1])?intval($matches[1]):0;
	if($from==='Me'){
		$flags=5;
		$address=$to;
	}
	else{
		$flags=4;
		$address=$from;
	}
	$timestamp=strtotime($startDate);
	$mcc='255';
	$mnc='01';
	$sql.="INSERT INTO call VALUES($rowId,'$address',$timestamp,$totalSeconds,$flags,-1,'','$mcc','$mnc',1,0,NULL,NULL);\n";
	$rowId++;
}
$sql.="COMMIT;\n";
fclose($handle);
file_put_contents($outputFile,$sql);
echo "SQL file generated: $outputFile\n";
?>

4. В DB Browser for SQLite выполнить подготовленные запросы, записать изменения.
5. В iBackupBot импортировать БД обратно.
6. Восстановить резервную копию через iTunes

Categories: iOS Tags:
27 ноября 2025 1 комментарий

если установлен squid без OpenSSL полностью удалить

sudo apt remove --purge squid squid-common squid-langpack
sudo apt autoremove
which squid

установить squid с поддержкой OpenSSL

sudo apt install squid-openssl
squid -v | grep -i ssl

создать каталог и самоподписанный CA (корневой сертификат для MITM) для динамической генерации сертификатов под сайты

sudo mkdir -p /etc/squid/ssl
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
	-keyout /etc/squid/ssl/ca.key \
	-out /etc/squid/ssl/ca.crt \
	-subj "/CN=Squid-CA/"
chmod 600 /etc/squid/ssl/ca.key

конфиг

mcedit /etc/squid/squid.conf

на 3128 прокси как было для всех с авторизацией, на 3130 специально для телефона с SSL-bump и без авторизации + MITM (с авторизацией он не может работать)

http_port 3128
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
auth_param basic children 5
auth_param basic realm Proxy Authentication
auth_param basic credentialsttl 2 hours
acl authenticated proxy_auth REQUIRED
http_port 3130 ssl-bump \
	generate-host-certificates=on dynamic_cert_mem_cache_size=4MB \
	cert=/etc/squid/ssl/ca.crt key=/etc/squid/ssl/ca.key
acl iphone_port myport 3130
acl step1 at_step SslBump1
ssl_bump peek step1
ssl_bump bump iphone_port
ssl_bump splice all
http_access allow iphone_port
http_access allow authenticated
http_access deny all
access_log /var/log/squid/access.log
cache_log /var/log/squid/cache.log

пароли для пользователей с авторизацией

htpasswd -c /etc/squid/passwords user
cat /etc/squid/passwords

инициализация SSL DB

security_file_certgen -c -s /var/spool/squid/ssl_db
sudo /usr/lib/squid/security_file_certgen -c -s /var/spool/squid/ssl_db -M 4MB

права

chown proxy:proxy /etc/squid/passwords
chmod 640 /etc/squid/passwords
sudo chown -R proxy:proxy /var/spool/squid
sudo chmod -R 755 /var/spool/squid

перезапуск

squid -k parse
squid -k reconfigure
systemctl restart squid

проверки

systemctl status squid.service
sudo tail -f /var/log/squid/cache.log
sudo tail -f /var/log/squid/access.log

ca.crt установить на iphone, передать, например, с помощью встроенного e-mail клиента
в текущем подключении wi-fi — сервер и порт, без авторизации

Categories: iOS Tags:
27 марта 2024 Нет комментариев
self.progressbar.trackTintColor = .white
self.progressbar.progressTintColor = UIColor(red:244/255.0, green: 66/255.0, blue: 8/255.0, alpha: 1)
Categories: iOS Tags:
27 марта 2024 Нет комментариев
func share(message: String, link: String){
	if let link = NSURL(string: link){
		let objectsToShare = [message, link] as [Any]
		let activityVC = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
		self.present(activityVC, animated: true, completion: nil)
	}
}
share(message: "test", link: "https://ya.ru/")

https://stackoverflow.com/questions/37938722/how-to-implement-share-button-in-swift

Categories: iOS Tags:
27 марта 2024 Нет комментариев
if(string.contains("?share")){
	let urlArr = string.components(separatedBy: "?")
	let link = urlArr[0]
}
Categories: iOS Tags:
1 февраля 2024 Нет комментариев

ios webview pull to refresh

override func viewDidLoad() {
	// after webView.load
	let refreshControl = UIRefreshControl()
	refreshControl.addTarget(self, action: #selector(reloadWebView(_:)), for: .valueChanged)
	webView.scrollView.addSubview(refreshControl)
}
@objc func reloadWebView(_ sender: UIRefreshControl){
	webView.reload()
	sender.endRefreshing()
}
Categories: iOS Tags: