# 关于文件读写库的设计，也许可以引入Object Capability

**URL:** <https://taolun.moonbitlang.com/t/topic/1126>\
**Category:** 欢迎\
**Created:** [2025 年1 月 19 日 22:12 UTC](https://taolun.moonbitlang.com/t/topic/1126 "2025-01-19T22:12:08Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

作者： ![FlyCloudC](https://taolun.moonbitlang.com/user_avatar/taolun.moonbitlang.com/flycloudc/32/653_2.png) [@FlyCloudC](https://taolun.moonbitlang.com/u/FlyCloudC)\
发布日期： [2025 年1 月 19 日 22:12 UTC](https://taolun.moonbitlang.com/t/topic/1126/1 "2025-01-19T22:12:08Z")

</div>

不像js或者c，moonbit这种静态类型且类型安全的语言，有这样一种特性：特定的某个对象是无法伪造的。所以可以考虑使用object capability的形式实现权限管理。简单的说，就是“如果你没有某个令牌对象的引用，就没法使用它所对应的权限”。

大致思路如下，以简单的文件读写为例：

1、在模块1中创建一个抽象类型`File`，作为文件读写权限的令牌，提供以下api：

```moonbit
pub fn get_file_from_path(path : String) -> File? {
  ... // 调用模块内部私有的ffi函数
}

pub fn read(self : File) -> String
pub fn write(self: File, text : String) -> Unit

```

2、在模块2中引入并导出模块1中的所有内容，_除了创建`File`的函数_。

3、定义安全模块：没有直接或间接依赖模块1的模块。

于是安全模块中只能读写 由不安全模块创建的文件。

同样的手段可以用来表示“获取File对象的权限”，即get\_file\_from\_path这个函数对象本身。以及“获取get\_file\_from\_path这个对象的权限”。

权限的细化也可以通过定义新的抽象类型或者闭包实现：

```moonbit
pub fn readonly(self : File) -> () -> String {
  fn() { self.read() }
}

```

或者像参考资料1那样。moonbit里可以用trait object。

除了文件库，任何需要管理权限的都可以参照这种形式，详见参考资料。

* * *

一些参考资料：

- scheme中的object capability ( [spritely-core](https://files.spritely.institute/papers/spritely-core.html#goblins) )
- From Desktops to Donuts: Object-Caps Across Scales ( [Youtube](https://m.youtube.com/watch?v=vrbmMPlCp3U) )
- 线性类型下的object capability ( [Austral语言](https://borretti.me/article/introducing-austral#cap) )
- [GitHub - dckc/awesome-ocap: Awesome Object Capabilities and Capability Security](https://github.com/dckc/awesome-ocap)

---

<div class="post-metadata">

作者： ![FlyCloudC](https://taolun.moonbitlang.com/user_avatar/taolun.moonbitlang.com/flycloudc/32/653_2.png) [@FlyCloudC](https://taolun.moonbitlang.com/u/FlyCloudC)\
发布日期： [2025 年1 月 19 日 22:34 UTC](https://taolun.moonbitlang.com/t/topic/1126/2 "2025-01-19T22:34:08Z")

</div>

再举个有意思的例子，可撤销的权限：

```moonbit
type CancelAble[A, B] Ref[((A) -> B)?]

pub fn new[A, B](cap : (A) -> B) -> (CancelAble[A, B], () -> Unit) {
  let ref = Ref::new(Some(cap))
  fn cancel() { ref.value = None }
  (ref, cancel)
}

pub fn use[A, B](self : CancelAble[A, B], arg : A) -> B? {
  match self._ {
    None => None
    Some(cap) => Some(cap(arg))
  }
}

pub fn valid(self : CancelAble[A, B]) -> Bool {
  self._.value != None
}

```

由于CancelAble在模块外是抽象的，所以使用者没法把CancelAble里的权限偷出来接着用

---

<div class="post-metadata">

作者： ![FlyCloudC](https://taolun.moonbitlang.com/user_avatar/taolun.moonbitlang.com/flycloudc/32/653_2.png) [@FlyCloudC](https://taolun.moonbitlang.com/u/FlyCloudC)\
发布日期： [2025 年1 月 19 日 23:11 UTC](https://taolun.moonbitlang.com/t/topic/1126/4 "2025-01-19T23:11:33Z")

</div>

重新设计1楼中文件读写的模块，可以得到一个比较有实际意义的例子：

删除原先的`get_file_from_path`，新增一个抽象类型`Dir`，并提供以下接口：

```moonbit
pub fn get_file(self : Dir, file_name : String) -> File!Error

pub fn get_dir(self : Dir, file_name : String) -> Dir!Error

pub fn make_dir(self : Dir, subdir_name : String) -> Dir

pub fn make_dir_abs(self : RootCapability, path : String) -> Dir

```

如果语言能支持设置main函数带有一个RootCapability类型的参数，且某个应用程序的main长这样：

```moonbit
fn main(root : RootCapability) {
  let my_dir = root.make_dir_abs("xxx")
  let config_file = my_dir.get_file!("config")
  let cache_dir = my_dir.get_dir!("cache")
  
  app_begin(config_file, cache_dir)
}

```

仅通过查看main函数，就能证明这个应用程序没有访问其它文件或目录的权限。
