如何绕过ChatGPT针对服务器提供商的IP封禁

今天早上一起来,发现新App审核又被拒了,但理由又是他们找不到IAP项目,遂怀疑是他们对汉语引导的理解问题,写了一段非常详尽的引导,然后打开ChatGPT,想翻译成英文,结果发现ChatGPT把我的IP ban了。

一开始,还以为也是其他人遇到的账号被封问题,但仔细一看是禁止了我的IP访问。我一直是用自建在Vultr上的服务器来进行专业上网的,虽然价格可能比某些服务贵些,但贵在稳定和安心。(5刀一个月,1000G流量,其实也还能接受了)

于是我在Vultr上直接新建了一个服务器,启动好之后配置一下,发现依然不行,不论是ipv6还是ipv4,也都不行,于是我想到估计是Vultr整体被封了,去搜了一下,才发现原来我还算是幸运的了,早两个月开始ChatGPT就已经开始大规模封禁来自各个云服务提供商的请求了,aws,GCP,Vultr这些大的提供商更是早就上了黑名单。但搜索之下,也找到了应对的办法,那就是利用魔法打败魔法。

ChatGPT是利用cloudflare来进行网络防护的,而cloudflare家自己,却出了一个安全上网和反嗅探的工具:Cloudflare Warp,也就是著名的1.1.1.1。

利用这个工具,我们只要在服务器端配置好了,既可以实现穿越ChatGPT的封锁。(注意,是在服务器端安装,在你本机安装并没有用,所以如果你并不是自有服务器,那么后续的内容对你来说可能用处就不大了)

下面是具体的操作步骤:

首先,登录你的服务器(比如ssh或者在云服务的官网找对应工具),在命令行里输入:

如果你的服务器是基于apt的(例如Ubuntu或者Debian)
sudo apt install cloudflare-warp
如果你服务器是基于yum的(例如centOS或者RHEL)
sudo yum install cloudflare-warp
安装好之后,继续运行如下的代码:
warp-cli register
如果成功,会显示一个Success

接下来这步比较关键,而且其实是有限制的一步,因为一旦开启warp之后,我们本地对服务器的访问,其实也会被限制,我目前只找到了一个添加例外IP的做法(其实还有个同样是cloudflare提供的zero trust的将你的服务器和本机组成类似内网的解决方案,但这个方案我个人是感觉限制过多而且过于依赖cloudflare了,万一哪天它也反了,就。。)

但添加例外IP,其实就是将本机的IP地址添加到warp的例外中,而我们都知道,除非你自己拉了根企业光纤有独立的IP地址,否则家用宽带的IP地址,就是一直在变的,这个也就是限制所在了,但一是我们的IP不会那么快变,二是连接之后只要你不断开,IP变了也是可以继续使用的,三是warp的例外支持网段,我们可以尽可能的扩大例外的规模,来减少我们失去例外的机会。

那么接下里就是去百度搜一下IP地址,找到你本机目前的IP,然后在服务器的命令行里,输入:
warp-cli add-excluded-route xx.xx.xx.xx
其中xx.xx.xx.xx就是你的IP地址,假如你想加入一个IP网段范围来减小失效的概率,可以将其改为:
xx.xx.0.0/16
注意!!!:上面这个网段,只是一个示例,表示从xx.xx.0.1到xx.xx.255.254之间的所有IP地址。在使用时,请确保里你理解这其中的风险以及网段的具体意义。(当然,允许这些IP访问不代表你的原本的其他安全鉴定会失效,这里只是针对warp的限制例外)
在完成上述步骤之后,可以运行下面的代码来开启warp(再次注意:如果你没添加上述规则,你的ssh将无法再连接,你只能通过云服务提供商提供的方法来连接了):
warp-cli connect
开启成功后,可以使用下面的代码来检查是否真正启动:
curl https://www.cloudflare.com/cdn-cgi/trace/
如果你看到返回的字段中,有warp=on存在,那就是开启成功了,下面你就可以继续请求访问ChatGPT了

一些可能遇到的问题和个人经验(及广告):

安装问题

在使用apt或apt-get安装时,返回了Unable to locate package的提示,那么可以考虑先运行
sudo apt update
来更新你的资源列表,但如果更新之后依然不行(比如我),那么cloudflare也提供了手动下载的方式,你可以在这个页面中找到对应的Linux版本的warp安装包:

https://pkg.cloudflareclient.com/packages/cloudflare-warp 找到对应的包之后,可以下载之后,利用注入scp之类的工具拷贝的服务器上,也可以复制下载链接,然后在服务器中运行:
curl -o name-of-your-file https://you-download-url
然后再进行安装,比如我的机器是Debian的,那么接下来我会运行:
sudo dpkg -i name-of-your-file
sudo apt-get install -f
然后就安装完毕了

IP网段问题

如果你还是觉得添加例外这个方法不靠谱,那么你可以继续研究cloudflare的zero trust方案,也欢迎你推出新的教程并告诉我,下面是对应的文档地址:

https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/use_cases/ssh/

服务器和专业上网(广告)

其实现在来说,影袜的方案,就我自己的经验来看,是非常容易被嗅探到的,尤其是那些常用的海外云服务,之前经常就是这个服务器我刚刚开好,安装好了影袜,结果没几分钟就被封了,而且是明显IP能ping通,但不论你怎么换端口也都不行了,但现在我用的方案,非常简单,无需安装额外的工具,而且只要IP能ping通,基本上就能稳定使用。那就是使用ssh自带的动态端口转发功能,只需要一行指令:
ssh -N -g -D 1088 username@xx.xx.xx.xx
即可在你本地的1088端口开放一个通道,如果你只是希望自己的本机使用,那么可以去掉-g指令,或者显式的声明127.0.0.1:1088,如果不加,则其实同个局域网的其他设备,也可以访问你的IP:1088来进行专业上网,比如手机上,可以直接用小火箭来访问,稍微修改下配置即可。

然后以Mac为例,则可以在自己的设置-网络-高级-你懂得里配置诸如socks或者http方案,以及例外域名或者PAC方案。当然,如果你想要方便的管理这些配置而不是每次都打开设置来操作,可以尝试下我开发的Mac App:

https://apps.apple.com/cn/app/proxyho/id6444635008?mt=12
当然ssh的方案,因为加密算法的原因,其实理论速度是会不如专门为了这个而生的影袜的,但个人感觉这些损耗可以忽略不计,毕竟安逸了许多

另外如果你看了本篇文章,希望选择服务器,那么我也推荐一下Vultr,我个人认为性价比还可以,而且它们的官网并不需要特殊的姿势就可以直接访问,也很友好,下面是我的推广链接,服务器都是按使用时长计费的,试用不满意,关了就好了。当然他们家用的人很多,那么就也会偶尔出现IP被ban的情况,但因为是按照时长收费的,遇到这种情况,关闭服务器再重新启动一个即可。

https://www.vultr.com/?ref=9418691-8H

对了,他们家还支持ipv6网络方案,也无需额外付费,只要勾选即可

解决SwiftUI中的透明view点击无法生效的问题

透明的view,无论是整体opacity设置为了0,还是颜色设置为了clear,在swiftUI中,默认的content shape (内容形状)就是0,所以点击事件是无法生效的,而要解决这个问题,我们只需要手动设置content shape即可 代码如下:
Color.clear
  .frame(width: 300, height: 300)
  .contentShape(Rectangle())     // 这里,当然上面的frame也有必要,如果frame为0,则肯定也无法触发点击
  .onTapGesture { print("tapped") } 

SwiftUI中如何自定义Navigation返回按钮

iOS15+

// 自定义的返回按钮,按照你的需求自己定制
struct NavBackButton: View {
    let dismiss: DismissAction
    
    var body: some View {
        Button {
            dismiss()
        } label: {
            Image("...custom back button here")
        }
    }
}

// 在要使用的view下,加入如下modifier
.navigationBarBackButtonHidden(true) // Hide default button
.navigationBarItems(leading: NavBackButton(dismiss: self.dismiss)) // Attach custom button
在引入了上述逻辑后,就会在child view中显示你的自定义的按钮,但同时,左滑返回的手势会失效,如果你需要保留这个手势,则还需要加入如下的代码:
// 让使用自定义返回按钮时,左滑返回的动画不失效,同时对child view是scrollview等也需要监听drag gesture的情况做了兼容
extension UINavigationController: UIGestureRecognizerDelegate {
    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }

    // To make it works also with ScrollView
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        true
    }
}

iOS15之前

struct SampleDetails: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    var btnBack : some View { Button(action: {
        self.presentationMode.wrappedValue.dismiss()
        }) {
            HStack {
            Image("ic_back") // set image here
                .aspectRatio(contentMode: .fit)
                .foregroundColor(.white)
                Text("Go back")
            }
        }
    }
    
    var body: some View {
            List {
                Text("sample code")
        }
        .navigationBarBackButtonHidden(true)
        .navigationBarItems(leading: btnBack)
    }
}

SwiftUI 如何让view强制支持横屏或竖屏

问题:有时候在编写APP时,我们会需要某个页面只支持手机的某个方向(并不是懒得适配,确信)。而在swiftUI中,要实现这个设定又变得更加复杂了,本篇文章就希望提供一个清晰且简单的解法,来支持这一点。

首先,我们需要swiftUI支持AppDelegate.

在非swiftUI中,这个文件是在创建项目的时候就会被系统一同创建的,但swiftUI并没有为我们创建这个文件,但这并不意味着swiftUI就无法连接到AppDelegate并作出响应

而其实建立连接也十分简单,首先,创建一个class,这里其实创建AppDelegate的任何方法都可以,但为了不重复赘述,我这里直接写好了后面屏幕方向设定会用到的方法

class AppDelegate: NSObject, UIApplicationDelegate {
static var orientationLock = UIInterfaceOrientationMask.portrait

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -&gt; UIInterfaceOrientationMask {
return AppDelegate.orientationLock
}
}

这个设定,是将APP支持的屏幕方向设置了只支持竖屏,当然,如果你的APP也仅仅想做到这一步,那其实在设置里也可以直接做到,不用专门写一个class

接下来,在某个我们希望只支持横屏的view中,只要写下如下代码,即可切换到横屏

import SwiftUI

struct DestinationView: View {

var body: some View {
Group {

Text("Hello")

}.onAppear {
AppDelegate.orientationLock = UIInterfaceOrientationMask.landscapeLeft
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
}
.onDisappear {
DispatchQueue.main.async {
AppDelegate.orientationLock = UIInterfaceOrientationMask.portrait
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()
}
}
}
}

要注意的是,UIDevice中设定Value时要使用rawValue,否则会报错,而在onDisappear方法中,要使用异步来保证当前view消失时,不会因为之前的view的屏幕朝向不同而报错

Docker container容器内访问宿主机host服务

问题:docker的container内,本身是一个微小的主机,那么请求127.0.0.1或者localhost,自然是请求到了container本身的网络,而无法抵达宿主机。

在以往,需要各位去手动寻找docker创建的docker0 bridge来访问宿主机网络,但在今天,docker已经提供了非常优雅的解决办法了

Linux:

Docker版本高于v20.10(2020年12月4日更新)

在启动docker时,加入如下语句
--add-host=host.docker.internal:host-gateway
而在container内,可以直接请求host.docker.internal:PORT,来获取宿主机上提供的各种服务

如果使用了Docker Compose,则应该将下面的句子加入container的声明中:

extra_hosts:
- "host.docker.internal:host-gateway"

Mac和Windows:

Docker版本高于v18.03(2018年3月21日更新)

直接在container内使用host.docker.internal:PORT来访问宿主机服务即可

对于Mac上Docker版本低于上述版本的:

Mac Docker版本v17.12到v18.02: 使用docker.for.mac.host.internal

Mac Docker版本v17.06到v18.11: 使用docker.for.mac.localhost

对于更低版本的docker,只能使用老旧的方法了,这里不再多做赘述

参考:https://stackoverflow.com/a/43541732

SwiftUI 遇到Simultaneous accesses to XXX, but modification requires exclusive access的解决办法

本质上这个问题是一个系统bug,swiftUI中,如果你的List下不完全是依靠Foreach加载的core data的数据的话(即,你在list中添加了其他的View,例如自己写了个自定义的Title等),而你又提供了删除或者移动row的方法时,就会出现这种错误。

这是由于swiftUI Foreach的onDelete的方法没有兼容上面所述的情况造成的

目前可以使用的的解决办法是这样的:
viewContext.perform {
            offsets.map { molts[$0] }.forEach(viewContext.delete)

            do {
                try viewContext.save()
            } catch {
                viewContext.rollback()
                userMessage = "\(error): \(error.localizedDescription)"
                displayMessage.toggle()
            }
}
在你的操作方法外,再套一层,调用viewContext.perform即可

使用SSH来连接远程服务器的MySQL

本文要解决什么问题:当远程服务器无法开放MySQL端口或者无权限操作远程服务器的安全组时,我们应该如何在本地连接到远程的MySQL并进行操作

本文基础要求:远程服务器至少开放了SSH端口(通常默认情况下端口号为22),如果未开放22端口,则本文所述方法并不可用。

本文方法总结:利用SSH自带的端口映射功能,建立一个tunnel,将远程服务器上的MySQL端口映射到本地的端口上,从而使得本地客户端可以直接连接

关于如何使用SSH,以及如何更简单的使用SSH,可以参考另一篇文章

当SSH已经准备就绪,打开Terminal,输入如下指令


ssh -L [local port]:[database host]:[remote port] [username]@[remote host]

ssh -L [本地端口]:[数据库所在地址]:[数据库远程端口] [远程服务器用户名]@[远程服务器地址]

*如果你不用同时登陆远程服务器进行操作,可以加上-N指令

以上指令唯一需要解释的就是数据库所在地址,如果远程服务器本身就是MySQL服务器,那么可以直接填127.0.0.1, 而如果远程服务器本身还是一个跳板,则应该输入在远程服务器内可以访问到MySQL的地址。

示例如下:

ssh -N -L 3310:127.0.0.1:3306 root@MyRemote

以上的命令会将远程服务器监听3306端口的MySQL服务,映射到本地的3310端口上,之后可以直接使用MySQL客户端在命令行里登录,或者使用pma等数据库操作工具

mysql -u root -h 127.0.0.1 -P 3310 -p

SwiftUI CoreData entity/实体更新导致无法预览的问题

最近改动了某个entity的类型,取消了它的继承,preview突然就停止工作了,一直提示crash,直接调用以下方法,清除之前的preview设定即可,因为preview里还保存了旧的设定,与新设定冲突,导致preview crash

xcrun simctl --set previews delete all

如何在SwiftUI中给字体加粗

swiftUI的文本设置,给了非常简单易懂的字体选择器,而如果想给字体加粗,该如何实现呢

这里就可以这样设置

TextField("Name", text: $name)
.font(Font.headline.weight(.light))

而可以选择的字体大小的,有如下的从小到大的名称

.caption
.footnote
.subheadline
.callout
.body
.headline
.title
.largeTitle

而字体粗细的选择,则有如下从细到粗的字段可选

.ultralight
.thin
.light
.regular
.medium
.semibold
.bold
.heavy
.black