「上書き保存(UAC対応)」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
Ks (トーク | 投稿記録)
ページの作成:「== 概要 == UAC に対応した「上書き保存」マクロです. == 変更履歴 == * 2013/1/27 初版 == 注意 == * 若干の副作用(制限)があります...」
 
Ks (トーク | 投稿記録)
バグ修正
1行目: 1行目:
== バグ ==
'''2013/2/1 以前までのコードにはセキュリティリスクのあるバグが含まれていました.'''<br>
申し訳ありません.
=== バグ詳細 ===
* 現象<br>ファイルのアクセス権限が書き換えられる.<br>結果として管理者権限がなくてもファイルを書き換えることが可能となる.<br>(実行時のユーザのアクセス権限がフルアクセスになる)
* 条件<br>TEMP がユーザフォルダ配下にある(デフォルト状態)
== 概要 ==
== 概要 ==
UAC に対応した「上書き保存」マクロです.
UAC に対応した「上書き保存」マクロです.
4行目: 13行目:
== 変更履歴 ==
== 変更履歴 ==
* 2013/1/27 初版
* 2013/1/27 初版
* 2013/2/2 バグ修正&UAC判定の強化


== 注意 ==
== 注意 ==
22行目: 32行目:
* 改行コードは固定
* 改行コードは固定
* 「外部でファイルが変更されています」のメッセージが表示される
* 「外部でファイルが変更されています」のメッセージが表示される
* UAC 制御画面でキャンセルしても編集マーク(*)が消える(実際には保存されていない)
<source lang="javascript">
<source lang="javascript">
#title="上書き保存(UAC対応)"
#title="上書き保存"


// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
34行目: 45行目:
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------


var NEWLINE_CODE = "\r\n";
var NEWLINE_CODE = "\r\n"


// UAC 不要な場合は通常保存
// 『無題』は通常処理
if (!NeedUAC(Document.FullName)){
if (!Document.Name) {
   Document.Save();
   Document.Save();
   Quit();
   Quit();
}
}


// 『無題』は保存対象外
// 変更がない場合は保存しない
if (!Document.Name) {
if (Document.Saved) {
  Quit();
}
 
// ファイルがない場合は通常処理(Mery準拠)
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (!fso.FileExists(Document.FullName)) {
  Document.Save();
   Quit();
   Quit();
}
}
// 変更がない場合は保存しない
 
if (Document.Saved) {
// 書き込み禁止か取得
var file = fso.GetFile(Document.FullName);
if (file.Attributes & 0x01) {
  Alert("このファイルは読み取り専用です");
   Quit();
   Quit();
}
}


// マークの更新
// UAC の判定
//すぐに反映されないので対処
if (!IsNeedUAC(Document.FullName)) {
Document.Saved = true;
   Document.Save();
var sel = Document.Selection;
   Quit();
if (sel.GetActivePointX(mePosLogical) == 1 && sel.GetActivePointY(mePosLogical) == 1) {
   sel.CharLeft();
} else {
   sel.CharLeft();
  sel.CharRight();
}
}


// 一時ファイルに保存して UAC 対応ムーブ
// 一旦別のファイルに保存して,UAC対応コピー処理
var shell = new ActiveXObject("Wscript.Shell");
var shell = new ActiveXObject("Wscript.Shell");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var tempFilePath = fso.BuildPath(folder, Document.Name);
var tempFilePath = fso.BuildPath(folder, Document.Name);
SaveToFile(tempFilePath, Document);
SaveToFile(tempFilePath, Document);


var appShell = new ActiveXObject("Shell.Application");
var appShell = new ActiveXObject("Shell.Application");
appShell.ShellExecute("cmd.exe", '/c MOVE /Y "' + tempFilePath +'" "' + Document.FullName + '"', "", "runas", 2);
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + Document.FullName + '" & DEL "' + tempFilePath + '"', "", "runas", 2);
UpdateSavedMark(true);
 
 
//==============================================================================
// 関数定義


// UAC が必要かを判定
// UAC が必要かを判定
function NeedUAC(path) {
function IsNeedUAC(path) {
   if (!path) {
   if (!path) {
     return false;
     return false;
  }
  // 書き込み可能か確認
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  try {
    fso.OpenTextFile(path, 8).Close();
    return false;
  } catch (e) {
    // 排他制御中でも同じ結果を返すが判別できない
   }
   }


83行目: 111行目:
   var oLocator = new ActiveXObject("WBemScripting.SWbemLocator");
   var oLocator = new ActiveXObject("WBemScripting.SWbemLocator");
   var oService = oLocator.ConnectServer();
   var oService = oLocator.ConnectServer();
   var os = new Enumerator(oService.ExecQuery("SELECT *FROM Win32_OperatingSystem"));
   var os = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_OperatingSystem"));
   if (Number(os.item().Version.substring(0, 3)) < 6.0) {
   if (Number(os.item().Version.substring(0, 3)) < 6.0) {
     return false;
     return false;
   }
   }


   // パス判定
   // ファイルの権限を確認
   path = path.toLowerCase().match(/^.*\\/)[0];
   var SE_DACL_AUTO_INHERITED = 0x0400;
   if (path == "c:\\" || path.indexOf("c:\\program files") >= 0 || path.indexOf("c:\\windows\\") >= 0) {
  var permission = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_LogicalFileSecuritySetting Where Path='" + path.replace(/\\/g, "\\\\") + "'"));
   if (!permission.atEnd() && permission.item().ControlFlags & SE_DACL_AUTO_INHERITED) {
     return true;
     return true;
   }
   }
99行目: 128行目:
// ファイル保存
// ファイル保存
function SaveToFile(path, doc) {
function SaveToFile(path, doc) {
   if (!charset) {
   var charset = "utf-8";
    var charset = "utf-8";
  switch (doc.Encoding) {
    switch (doc.Encoding) {
    case meEncodingEUC:                   charset = "euc-JP";  break;
      case meEncodingEUC:           charset = "euc-JP";  break;
    case meEncodingShiftJIS:             charset = "shift-jis";  break;
      case meEncodingShiftJIS:       charset = "shift-jis";  break;
    case meEncodingUTF16LE:
      case meEncodingUTF16LE:
    case meEncodingUTF16BE:               charset = "unicode";  break;
      case meEncodingUTF16BE:         charset = "unicode";  break;
    case meEncodingUTF7:                 charset = "utf-7";    break;
      case meEncodingUTF7:         charset = "utf-7";    break;
    case meEncodingUTF8WithSignature:
      case meEncodingUTF8WithSignature:
    case meEncodingUTF8WithoutSignature:  charset = "utf-8";    break;
      case meEncodingUTF8WithoutSignature:  charset = "utf-8";    break;
    }
   }
   }
   var adodb = new ActiveXObject("ADODB.Stream");
   var adodb = new ActiveXObject("ADODB.Stream");
   adodb.Charset = charset;
   adodb.Charset = charset;
118行目: 146行目:


   // BOM 削除処理
   // BOM 削除処理
   if (charset.toLowerCase() === ("utf-8")) {
   if (doc.Encoding == meEncodingUTF8WithoutSignature) {
     adodb.Position = 0;
     adodb.Position = 0;
     adodb.Type = 1;
     adodb.Type = 1;
132行目: 160行目:
   adodb.Close();
   adodb.Close();
};
};
// マークの更新
// すぐに反映されないので対処
function UpdateSavedMark(isSaved) {
  if (Document.Saved != isSaved) {
    Document.Saved = isSaved;
    var sel = Document.Selection;
    if (sel.GetActivePointX(mePosLogical) == 1 && sel.GetActivePointY(mePosLogical) == 1) {
      sel.CharLeft();
    } else {
      sel.CharLeft();
      sel.CharRight();
    }
  }
}
</source>
</source>


149行目: 192行目:
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------


// UAC 不要な場合は通常保存
// 『無題』は通常処理
if (!NeedUAC(Document.FullName)){
if (!Document.Name) {
   Document.Save();
   Document.Save();
   Quit();
   Quit();
}
}


// 『無題』は保存対象外
// 変更がない場合は保存しない
if (!Document.Name) {
if (Document.Saved) {
  Quit();
}
 
// ファイルがない場合は通常処理(Mery準拠)
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (!fso.FileExists(Document.FullName)) {
  Document.Save();
  Quit();
}
 
// 書き込み禁止か取得
var file = fso.GetFile(Document.FullName);
if (file.Attributes & 0x01) {
  Alert("このファイルは読み取り専用です");
   Quit();
   Quit();
}
}
// 変更がない場合は保存しない
 
if (Document.Saved) {
// UAC の判定
if (!IsNeedUAC(Document.FullName)) {
  Document.Save();
   Quit();
   Quit();
}
}


var shell = new ActiveXObject("Wscript.Shell");
var shell = new ActiveXObject("Wscript.Shell");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var tempFilePath = fso.BuildPath(folder, Document.Name);
var tempFilePath = fso.BuildPath(folder, Document.Name);
181行目: 239行目:
Document.Save(tempFilePath);
Document.Save(tempFilePath);
var appShell = new ActiveXObject("Shell.Application");
var appShell = new ActiveXObject("Shell.Application");
appShell.ShellExecute("cmd.exe", '/c MOVE /Y "' + tempFilePath +'" "' + filePath + '"', "", "runas", 2);
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + filePath + '" & DEL "' + tempFilePath + '"', "", "runas", 2);


// ファイルムーブの完了をポーリング(最大 1 秒)
// ファイルムーブの完了待ち(最大 1 秒)
for (var i=0; i<50; i++) {
for (var i=0; i<50; i++) {
   Sleep(20);
   Sleep(20);
201行目: 259行目:
doc.Selection.SetAnchorPoint(mePosLogical, bx, by);
doc.Selection.SetAnchorPoint(mePosLogical, bx, by);
ScrollX = sx; ScrollY = sy;
ScrollX = sx; ScrollY = sy;
//==============================================================================
// 関数定義


// UAC が必要かを判定
// UAC が必要かを判定
function NeedUAC(path) {
function IsNeedUAC(path) {
   if (!path) {
   if (!path) {
     return false;
     return false;
  }
  // 書き込み可能か確認
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  try {
    fso.OpenTextFile(path, 8).Close();
    return false;
  } catch (e) {
    // 排他制御中でも同じ結果を返すが判別できない
   }
   }


212行目: 283行目:
   var oLocator = new ActiveXObject("WBemScripting.SWbemLocator");
   var oLocator = new ActiveXObject("WBemScripting.SWbemLocator");
   var oService = oLocator.ConnectServer();
   var oService = oLocator.ConnectServer();
   var os = new Enumerator(oService.ExecQuery("SELECT *FROM Win32_OperatingSystem"));
   var os = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_OperatingSystem"));
   if (Number(os.item().Version.substring(0, 3)) < 6.0) {
   if (Number(os.item().Version.substring(0, 3)) < 6.0) {
     return false;
     return false;
   }
   }


   // パス判定
   // ファイルの権限を確認
   path = path.toLowerCase().match(/^.*\\/)[0];
   var SE_DACL_AUTO_INHERITED = 0x0400;
   if (path == "c:\\" || path.indexOf("c:\\program files") >= 0 || path.indexOf("c:\\windows\\") >= 0) {
  var permission = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_LogicalFileSecuritySetting Where Path='" + path.replace(/\\/g, "\\\\") + "'"));
   if (!permission.atEnd() && permission.item().ControlFlags & SE_DACL_AUTO_INHERITED) {
     return true;
     return true;
   }
   }

2013年2月2日 (土) 10:41時点における版

バグ

2013/2/1 以前までのコードにはセキュリティリスクのあるバグが含まれていました.
申し訳ありません.

バグ詳細

  • 現象
    ファイルのアクセス権限が書き換えられる.
    結果として管理者権限がなくてもファイルを書き換えることが可能となる.
    (実行時のユーザのアクセス権限がフルアクセスになる)
  • 条件
    TEMP がユーザフォルダ配下にある(デフォルト状態)


概要

UAC に対応した「上書き保存」マクロです.

変更履歴

  • 2013/1/27 初版
  • 2013/2/2 バグ修正&UAC判定の強化

注意

  • 若干の副作用(制限)があります.
  • 環境変数「TEMP」にアクセスします.
  • 「TEMP」フォルダ配下の同名ファイルを書き換えます.

使用方法

  1. コードを js ファイルにしてマクロを登録する.
  2. 必要があれば,Ctrl+S に登録する.

コード

副作用(制限)が異なる 2 パターンのコードがあるので, より制限を許容できる方のコードをご使用ください.

パターン1

副作用(制限)

  • 改行コードは固定
  • 「外部でファイルが変更されています」のメッセージが表示される
  • UAC 制御画面でキャンセルしても編集マーク(*)が消える(実際には保存されていない)
#title="上書き保存"

// -----------------------------------------------------------------------------
// Overwrite.js
//
// UAC対応の上書き保存
//
// (C) ks
// http://merysmacro.seesaa.net/
// -----------------------------------------------------------------------------

var NEWLINE_CODE = "\r\n"

// 『無題』は通常処理
if (!Document.Name) {
  Document.Save();
  Quit();
}

// 変更がない場合は保存しない
if (Document.Saved) {
  Quit();
}

// ファイルがない場合は通常処理(Mery準拠)
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (!fso.FileExists(Document.FullName)) {
  Document.Save();
  Quit();
}

// 書き込み禁止か取得
var file = fso.GetFile(Document.FullName);
if (file.Attributes & 0x01) {
  Alert("このファイルは読み取り専用です");
  Quit();
}

// UAC の判定
if (!IsNeedUAC(Document.FullName)) {
  Document.Save();
  Quit();
}

// 一旦別のファイルに保存して,UAC対応コピー処理
var shell = new ActiveXObject("Wscript.Shell");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var tempFilePath = fso.BuildPath(folder, Document.Name);
SaveToFile(tempFilePath, Document);

var appShell = new ActiveXObject("Shell.Application");
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + Document.FullName + '" & DEL "' + tempFilePath + '"', "", "runas", 2);
UpdateSavedMark(true);


//==============================================================================
// 関数定義

// UAC が必要かを判定
function IsNeedUAC(path) {
  if (!path) {
    return false;
  }

  // 書き込み可能か確認
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  try {
    fso.OpenTextFile(path, 8).Close();
    return false;
  } catch (e) {
    // 排他制御中でも同じ結果を返すが判別できない
  }

  // OS 判定
  // XP 以前は不要
  var oLocator = new ActiveXObject("WBemScripting.SWbemLocator");
  var oService = oLocator.ConnectServer();
  var os = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_OperatingSystem"));
  if (Number(os.item().Version.substring(0, 3)) < 6.0) {
    return false;
  }

  // ファイルの権限を確認
  var SE_DACL_AUTO_INHERITED = 0x0400;
  var permission = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_LogicalFileSecuritySetting Where Path='" + path.replace(/\\/g, "\\\\") + "'"));
  if (!permission.atEnd() && permission.item().ControlFlags & SE_DACL_AUTO_INHERITED) {
    return true;
  }

  return false;
}

// ファイル保存
function SaveToFile(path, doc) {
  var charset = "utf-8";
  switch (doc.Encoding) {
    case meEncodingEUC:                   charset = "euc-JP";   break;
    case meEncodingShiftJIS:              charset = "shift-jis";  break;
    case meEncodingUTF16LE:
    case meEncodingUTF16BE:               charset = "unicode";  break;
    case meEncodingUTF7:                  charset = "utf-7";    break;
    case meEncodingUTF8WithSignature:
    case meEncodingUTF8WithoutSignature:  charset = "utf-8";    break;
  }

  var adodb = new ActiveXObject("ADODB.Stream");
  adodb.Charset = charset;
  adodb.Type = 2;
  adodb.Open();
  adodb.WriteText(doc.Text.replace(/\n/mg, NEWLINE_CODE));

  // BOM 削除処理
  if (doc.Encoding == meEncodingUTF8WithoutSignature) {
    adodb.Position = 0;
    adodb.Type = 1;
    adodb.Position = 3;
    var binary = adodb.Read();
    adodb.Close();

    // 新規ストリームに BOM を除いた文字列を書き込む
    adodb.Open();
    adodb.Write(binary);
  }
  adodb.SaveToFile(path, 2);
  adodb.Close();
};

// マークの更新
// すぐに反映されないので対処
function UpdateSavedMark(isSaved) {
  if (Document.Saved != isSaved) {
    Document.Saved = isSaved;
    var sel = Document.Selection;
    if (sel.GetActivePointX(mePosLogical) == 1 && sel.GetActivePointY(mePosLogical) == 1) {
      sel.CharLeft();
    } else {
      sel.CharLeft();
      sel.CharRight();
    }
  }
}

パターン2

副作用(制限)

  • 元に戻す,やり直しの履歴が削除される
#title="上書き保存"

// -----------------------------------------------------------------------------
// Overwrite.js
//
// UAC対応の上書き保存
//
// (C) ks
// http://merysmacro.seesaa.net/
// -----------------------------------------------------------------------------

// 『無題』は通常処理
if (!Document.Name) {
  Document.Save();
  Quit();
}

// 変更がない場合は保存しない
if (Document.Saved) {
  Quit();
}

// ファイルがない場合は通常処理(Mery準拠)
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (!fso.FileExists(Document.FullName)) {
  Document.Save();
  Quit();
}

// 書き込み禁止か取得
var file = fso.GetFile(Document.FullName);
if (file.Attributes & 0x01) {
  Alert("このファイルは読み取り専用です");
  Quit();
}

// UAC の判定
if (!IsNeedUAC(Document.FullName)) {
  Document.Save();
  Quit();
}

var shell = new ActiveXObject("Wscript.Shell");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var tempFilePath = fso.BuildPath(folder, Document.Name);

// 保存前の状態を保持
var sel = Document.Selection;
var latestText = Document.Text;
var sx = ScrollX, sy = ScrollY;
var tx = sel.GetTopPointX(mePosLogical), ty = sel.GetTopPointY(mePosLogical);
var bx = sel.GetBottomPointX(mePosLogical), by = sel.GetBottomPointY(mePosLogical);
var filePath = Document.FullName;

// 一時ファイルに保存して UAC 対応ムーブ
Document.Saved = true;
Document.Save(tempFilePath);
var appShell = new ActiveXObject("Shell.Application");
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + filePath + '" & DEL "' + tempFilePath + '"', "", "runas", 2);

// ファイルムーブの完了待ち(最大 1 秒)
for (var i=0; i<50; i++) {
  Sleep(20);
  if (!fso.FileExists(tempFilePath)) {
    break;
  }
}

// ファイルを開き直す
// UACの昇格を拒否されていた場合は,エディタ上の内容だけ書き換え
Editor.OpenFile(filePath);
var doc = Editor.ActiveDocument
if (doc.Text != latestText) {
  doc.Text = latestText;
}
doc.Selection.SetActivePoint(mePosLogical, tx, ty);
doc.Selection.SetAnchorPoint(mePosLogical, bx, by);
ScrollX = sx; ScrollY = sy;


//==============================================================================
// 関数定義

// UAC が必要かを判定
function IsNeedUAC(path) {
  if (!path) {
    return false;
  }

  // 書き込み可能か確認
  var fso = new ActiveXObject("Scripting.FileSystemObject");
  try {
    fso.OpenTextFile(path, 8).Close();
    return false;
  } catch (e) {
    // 排他制御中でも同じ結果を返すが判別できない
  }

  // OS 判定
  // XP 以前は不要
  var oLocator = new ActiveXObject("WBemScripting.SWbemLocator");
  var oService = oLocator.ConnectServer();
  var os = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_OperatingSystem"));
  if (Number(os.item().Version.substring(0, 3)) < 6.0) {
    return false;
  }

  // ファイルの権限を確認
  var SE_DACL_AUTO_INHERITED = 0x0400;
  var permission = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_LogicalFileSecuritySetting Where Path='" + path.replace(/\\/g, "\\\\") + "'"));
  if (!permission.atEnd() && permission.item().ControlFlags & SE_DACL_AUTO_INHERITED) {
    return true;
  }

  return false;
}


ご意見・ご要望

何かありましたら,右の [編集] から追記してください.対応するもかしれません.

スポンサーリンク