1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
# -*- coding: utf-8 -*-
miquire :core, 'environment'
require 'fileutils'
require 'openssl'
require 'securerandom'
class Service
module SaveData
ACCOUNT_FILE = File.join(Environment::SETTINGDIR, 'core', 'token').freeze
ACCOUNT_TMP = (ACCOUNT_FILE + ".write").freeze
extend SaveData
@@service_lock = Monitor.new
def key
UserConfig[:account_crypt_key] ||= SecureRandom.hex end
# 全てのアカウント情報をオブジェクトとして返す
# ==== Return
# account_id => {token: ,secret:, ...}
def accounts
@account_data ||= @@service_lock.synchronize do
if FileTest.exist? ACCOUNT_FILE
File.open(ACCOUNT_FILE, 'rb'.freeze) do |file|
YAML.load(decrypt(file.read)) end
else
# 旧データの引き継ぎ
result = UserConfig[:accounts]
if result.is_a? Hash
# 0.3開発版のデータがある
account_write result.inject({}){ |hash, item|
key, value = item
hash[key] = value.merge(provider: :twitter, slug: key)
hash }
elsif UserConfig[:twitter_token] and UserConfig[:twitter_secret]
# 0.2.x以前のアカウント情報
account_write({ default: {
provider: :twitter,
slug: :default,
token: UserConfig[:twitter_token],
secret: UserConfig[:twitter_secret],
user: UserConfig[:verify_credentials] } })
else
{} end end end end
# アカウント情報を返す
# ==== Args
# [name] アカウントのキー(Symbol)
# ==== Return
# アカウント情報(Hash)
def account_data(name)
accounts[name.to_sym] or raise ArgumentError, 'account data `#{name}\' does not exists.' end
# 新しいアカウントの情報を登録する
# ==== Args
# [name] アカウントのキー(Symbol)
# [options] アカウント情報(Hash)
# ==== Exceptions
# ArgumentError name のサービスが既に存在している場合、optionsの情報が足りない場合
# ==== Return
# Service
def account_register(name, options)
name = name.to_sym
@@service_lock.synchronize do
raise ArgumentError, "account #{name} already exists." if accounts.has_key? name
@account_data = account_write accounts.merge name => {
provider: (options[:provider] or raise ArgumentError, 'options requires key `provider\'.'),
slug: (options[:slug] or raise ArgumentError, 'options requires key `slug\'.'),
token: (options[:token] or raise ArgumentError, 'options requires key `token\'.'),
secret: (options[:secret] or raise ArgumentError, 'options requires key `secret\'.'),
user: (options[:user] or raise ArgumentError, 'options requires key `user\'.') } end
self end
# アカウント情報を更新する
# ==== Args
# [name] アカウントのキー(Symbol)
# [options] アカウント情報(Hash)
# ==== Exceptions
# ArgumentError name のサービスが存在しない場合
# ==== Return
# Service
def account_modify(name, options)
name = name.to_sym
@@service_lock.synchronize do
raise ArgumentError, "account #{name} is not exists." unless accounts.has_key? name
account_data = accounts[name].merge(options)
Plugin.call(:image_file_cache_cache, account_data[:user][:profile_image_url])
@account_data = account_write(accounts.merge(name => account_data)) end
self end
# 垢消しの時間だ
# ==== Args
# [name]
# ==== Return
# Service
def account_destroy(name)
name = name.to_sym
@@service_lock.synchronize do
to_delete = accounts.dup
to_delete.delete(name)
@account_data = account_write(to_delete) end
self end
# アカウント情報をファイルに保存する
def account_write(account_data = @account_data)
FileUtils.mkdir_p File.dirname(ACCOUNT_FILE)
File.open(ACCOUNT_TMP, 'wb'.freeze) do |file|
file << encrypt(YAML.dump(account_data)) end
FileUtils.mv(ACCOUNT_TMP, ACCOUNT_FILE)
account_data end
def encrypt(str)
cipher = OpenSSL::Cipher.new('bf-ecb').encrypt
cipher.key = key
cipher.update(str) << cipher.final end
def decrypt(binary_data)
cipher = OpenSSL::Cipher.new('bf-ecb').decrypt
cipher.key = key
str = cipher.update(binary_data) << cipher.final
str.force_encoding(Encoding::UTF_8)
str end
end
end
|