GASを使ったGoogleDrive権限管理について真剣に考えてみた

こんにちは！
Qiita初投稿にして初AdventCalendarです。
お手柔らかにお願いします！笑

## 背景

社内での資料共有は主にGoogleDriveを使用しています。
(GSuiteアカウントは一部部署・役職のみが使用、それ以外は社用メールアドレスの紐付いたGoogleアカウントに対して権限付与する運用。使用頻度とコストを考えると、全社員にGSuiteアカウントを払い出すほどではないかなーといった感じ)

リアルタイムで複数人と編集できたりして便利な反面、組織規模が大きくなるにつれ、色んなカオスが生み出されることに...

そこで今一度**運用ルールを整備する**とともに、**定期的に状態を確認するための仕組みを作る**というのが今回のミッションです！

## 前提知識

GAS云々の前に、GoogleDriveの権限についてのそもそものお話...

#### 意識すべきポイント

厳密な権限管理を行おうとすると、以下の5点が鍵となると考えています。

0. **権限**：編集／参照（コメント可）／参照（コメント不可）を適切に使い分ける
0. **編集者による権限変更**：原則許容しない（デフォルトは許可設定になっている）
0. **リンクによる共有**：原則使用しない。唯一使うとすれば、社内の誰でも閲覧可能な資料に"同一ドメイン下のリンクを知っている人は誰でも閲覧可"を設定するくらい
0. **オーナー権**：オーナーが組織を離れる(異動・退職)際には正しく後任に譲渡する
0. **閲覧者による印刷・DL・コピー**：（Google製アプリファイルのみ）原則許容しない

調べたところ、1〜4は**DriveAppクラス**を使用したGAS経由での操作が可能です。
5やフォルダ間移動も本来はスクリプトで制御できると良いんですが、今のところ探し切れていません(´･ω･`)

#### 各種設定と親子関係

以下を例に説明します。
一般的なファイルサーバだと、**階層が深くなればなるほど権限範囲が狭くなるよう設計することが多い**ので、個人的には感覚が掴みづらいなぁと思いました。


```
Folder_A
 ├ Folder_B
 | 　└ File_C
 ├ File_D
 └ shortcut_E
    
......
    
Folder_F
    
```

**権限設定は子孫に引き継がれる**：Folder_Aに対して行った権限設定は配下のFolder_B〜shortcut_Eにも反映される（ショートカットについての注意事項は後述）。ただし、基本後勝ちなので、後から子孫ファイルの権限を操作した場合、親フォルダの編集者≠子孫フォルダの編集者となる。

**移動すると移動前の編集者＋移動先の編集者に権限付与される**：太郎さん・花子さんが編集可能なFile_Dを、二郎さんが編集可能なFolder_F配下に移動した場合、太郎さん・花子さん・二郎さん全員がFile_Dを編集可能となる

**編集者による権限変更許可設定は子孫に引き継がれない**：こちらはフォルダ/ファイル単位で管理されているものらしく、個別に設定が必要（ブラウザだと、右クリック→共有→右上の歯車から設定が可能。自身がオーナーの場合のみ）


#### ショートカットという名のトラップ

普段使う分には動線が良くなって便利なんですが、こいつが結構厄介な仕組みになっています。

**ファイルの一種である**：クラスで言うとFolderではなくFile（MIMEType: application/vnd.google-apps.shortcut）

**親ファイルに対して権限変更した場合**：配下のショートカットは見えるようになるが、実態の権限は適用されない（ショートカット自体は見えるようになるが、アクセス不可）

**ショートカットに対して権限変更した場合**：ブラウザ上で操作すると実態の権限が変更されるが、GASにてショートカットに対して権限操作すると実態の権限は変更されない
※ ブラウザ操作では、裏でショートカットに対応する実態に対して権限変更する仕様になっているっぽい

# To be：設計思想

上記を踏まえると、**ドライブのフォルダ構成はフラットであればあるほど良い**と言えると思います。
今回は以下のポリシーに則って階層を整理した上で、権限管理用のGASを作成していきます。


* 権限範囲単位でフォルダを作成し、ネストは最小限にとどめる
* 子孫フォルダ・ファイルには直接権限を付与しない
* URLによる共有・共同編集者による権限編集を制限する

# To do：やりたいこと

GASで実現したいことは以下です。
権限グループとそれに属する人、および各フォルダのアクセス権はスプレッドシートにて管理する想定です。

* 権限操作
    * 全般
        * 一旦全編集権限を削除する
        * オーナー以外による権限編集を禁止する
    * 親フォルダ
        * 適切な人へ権限を付与し直す（付与し直すことで子孫フォルダへも反映される）
* 警告出力
    * 全般
        * リンクによる共有が許可されている場合
        * オーナーが当該フォルダの権限グループに属していない場合
        * すでに編集者以外による権限操作が禁止されていて、本来すべき権限操作ができなかった場合

# How：GASでどう実現するか

具体的な処理順（ざっくり）について。

0. 権限グループ取得
1. 子ディレクトリ取得 →再帰的に処理呼び出し
2. 子ファイル取得 →再帰的に処理呼び出し
3. オーナーのチェック
4. リンクによる共有のチェック
5. 編集権限剥奪
6. （トップ階層のみ）編集権限再付与
7. 編集者による権限編集禁止

ポイントは

* **階層深→浅の順に再起的に処理を行う**：都度権限を付与するのは手間（だし、メールもバンバン飛んじゃう）なので、最後に親フォルダに対して権限を付与することで、子孫フォルダへ踏襲させる
* **権限操作が終わってから、編集者による権限変更を禁止する**：でないと、スクリプト実行者がオーナーでないものは全部権限操作できなくなってしまうため(^-^;)


です。
（ゆくゆくはソースベースで解説記事書けると良いなぁと思っています）

# おわりに

調べながらちまちま作ったところ、まだ粗は残るものの、一通りやりたいことは実現することができました！

#### 今後の課題

**リンクによる共有設定**
"誰でも"と"同一ドメイン下"の両方が設定されていると例外が発生するっぽい？のでその対処

**ホワイトリスト化の検討**
他部署への連携等で特定ファイルに特例で権限を付与したい場合の考慮

**起動時間問題**
配下ファイル数や処理の内容によってタイムアウトになる（いかんともしがたいけど）

**ハリネズミのジレンマ**

* 編集者による権限編集をオンにすると、自由な権限編集が可能になってしまう
* 編集者による権限編集をオフにすると、GASによる権限編集が不可能になってしまう

→編集者による権限編集を許容してこまめに機械的にチェックするのが良いのか、はたまた編集権限をオーナーに一任するのが良いのか...（ケースバイケースな部分も大いにあるが）

#### 公式ドキュメントが神
下手にサンプルソース検索するより分かりやすかったです
https://developers.google.com/apps-script/reference

#### ご利用は計画的に

権限付与に際しては該当者にメールが飛ぶので慎重に行いましょう（みんなごめん）
suicideにはくれぐれもお気をつけて...w